Demoscene.fr BBS

Articles et discussions techniques => Code => Topic started by: flure on 27 November 2010 à 23:42:45

Title: Raymarching - besoin d'explications
Post by: flure on 27 November 2010 à 23:42:45
Salut à tous,

Je compte maintenant m'attaquer au raymarching, c'est un peu la mode en ce moment, faut bien que je me tienne à jour ;)

Donc je crois avoir à peu près compris le principe, mais je ne suis pas certain. En premier lieu je ne vois pas la différence avec le raycasting, comme on le fait par exemple pour un freedirectional tunnel.

Ce que j'ai compris : on envoie un rayon de qui part de l'oeil et qui passe par le pixel. On le fait avancer par pas d'une certaine distance, et à chaque pas on utilise une fonction de distance qui renvoie la distance au point de l'espace le plus proche. Quand cette distance est suffisamment faible, on diminue la taille du pas, suivant la résolution désirée, jusqu'à ce que la fonction de distance renvoie une valeur suffisamment faible pour qu'on considère qu'on est arrivé. De là on obtient la couleur du pixel.

J'ai bon ?

Pour info je voudrais utiliser le raymarching pour faire du rendu de metaballs en soft, sans passer par les marching cubes. Peut-être que je devrais m'attaquer en premier à quelque chose de plus simple, comme des sphères ou des plans ?

Voilà, toute aide sera la bienvenue, et je vous tiendrai bien sûr au courant de l'évolution de mes essais sur le sujet :)
Title: Re : Raymarching - besoin d'explications
Post by: xoofx on 28 November 2010 à 00:49:00
Ce que j'ai compris : on envoie un rayon de qui part de l'oeil et qui passe par le pixel. On le fait avancer par pas d'une certaine distance, et à chaque pas on utilise une fonction de distance qui renvoie la distance au point de l'espace le plus proche. Quand cette distance est suffisamment faible, on diminue la taille du pas, suivant la résolution désirée, jusqu'à ce que la fonction de distance renvoie une valeur suffisamment faible pour qu'on considère qu'on est arrivé. De là on obtient la couleur du pixel.
J'ai bon ?
Ouip!  ;)
Quote
Pour info je voudrais utiliser le raymarching pour faire du rendu de metaballs en soft, sans passer par les marching cubes. Peut-être que je devrais m'attaquer en premier à quelque chose de plus simple, comme des sphères ou des plans ?
Le plus simple est de travailler sur une scène basique qui contient effectivement une sphère. Tu valideras l'algo. Ensuite, tu peux travailler sur un peu n'importe quoi...
Title: Re : Raymarching - besoin d'explications
Post by: Patapom on 28 November 2010 à 00:49:34
J'imagine que t'as lu http://www.iquilezles.org/www/material/nvscene2008/rwwtt.pdf (http://www.iquilezles.org/www/material/nvscene2008/rwwtt.pdf) ?

Je t'avouerais que j'ai découvert les distance fields grâce à U2 qui m'a filé ce même lien il y a à peine une semaine ! J'ai déjà fait des tests pour voir mais mes rayons manquent parfois leur cible, j'ai dû rater des trucs essentiels parce que j'ai besoin de beaucoup de steps et au bout de 64 je m'arrête et ça touche pas forcément la destination.

Voici une image en fausses couleurs d'une sphère avec du noise avec 64 steps par rayon maximum (en rouge) :
(http://imgur.com/SHnWI.png)

Quand c'est violet c'est l'infini donc pas besoin de tracer de rayons. Quand c'est noir c'est qu'il est pas arrivé au hit après 64 rayons, en gros, là où j'ai échoué.
J'ai pas beaucoup poussé plus loin vu que je suis sur d'autres trucs en ce moment.

Mais oui tu as bien cerné le principe : en gros tu évalues la distance à l'objet le plus proche à chaque point de ton rayon. Ca te permet d'avoir une limite maximale du pas auquel tu peux avancer avant de risquer de toucher un objet...
Le problème vient évidemment des rayons rasants puisque tu te rapproches continuellement de la surface sans forcément jamais la toucher... Du coup t'avances seulement un tout petit peu à chaque fois, c'est le paradoxe de Zénon all over again !

D'après Iñigo, tu peux fixer une taille de step minimale pour être certain de toujours avancer d'au moins un certain pas. Et tu peux aussi tirer avantage du fait que l'erreur diminue avec la distance à la caméra donc faire en sorte que tes pas de rayons soient proportionnels à cette même distance.
J'ai eu beau faire joujou avec ce pas minimum et cette correction par la distance à la caméra, j'ai toujours de la merde.

Bref. Disons que tu trouves bien ton intersection quelque part, après il s'agit de récupérer la normale à la surface, calculer l'ombrage et l'ambient occlusion.
Je vais pas paraphraser Iñigo puisque tout est expliqué dans son PDF mais ça reste assez simple. Le plus difficile restant vraiment à trouver correctement l'intersection en un minimum de steps...


Pour ce qui concerne la différence avec du ray-casting : là tu codes la distance d'un objet par rapport à un point.
En ray-tracing tu calcule carrément l'intersection du rayon avec l'objet avec une formule (pas forcément super simple selon l'objet à intersecter).

Par exemple pour un cube qui est pas le plus simple :
Title: Re : Raymarching - besoin d'explications
Post by: zerkman on 28 November 2010 à 10:41:51
ha oui j'ai entendu parler de ça récemment, mais je ne vois vraiment pas l'interêt face à du vrai raycasting où tu tombes directement sur ta cible.

Exemple : une sphère de rayon r et dont le centre a les coordonnées c=(xc, yc, zc). Tu lances ton rayon à partir de l'origine o=(xo, yo, zo), avec un vecteur direction d=(xd, yd, zd) - vecteur unitaire (= dont la norme vaut 1). Tu résous l'équation ||o + t*d - c||2 = r2, si une solution existe tu trouves une distance t entre le point o et l'intersection rayon/sphère. Ton point d'intersection est donc égal à o+t*d.

L'exemple est expliqué là (http://www.siggraph.org/education/materials/HyperGraph/raytrace/rtinter1.htm).

Ca se fait en un seul coup, pas de méthode itérative. Tu choisiras finalement le point le plus proche parmi les intersections avec tous les objets (ie la valeur t positive la plus faible). Il y a des algos pour éviter de calculer les intersections avec tous les objets de la scène.

D'où ma question : qu'est-ce que le "raymarching" apporte ? Ca sert à quoi de découper la recherche itérativement, et surtout est-ce que ça garantit qu'on trouve à coup sûr l'objet le plus proche sans le rater ? C'est quoi la théorie derrière ?
Title: Re : Raymarching - besoin d'explications
Post by: nystep on 28 November 2010 à 11:04:44
Quote
Quand cette distance est suffisamment faible, on diminue la taille du pas, suivant la résolution désirée, jusqu'à ce que la fonction de distance renvoie une valeur suffisamment faible pour qu'on considère qu'on est arrivé. De là on obtient la couleur du pixel.

En fait non, tu incrémentes ton T de la valeur de la distance à la géométrie la plus proche, ce qui garantit que la nouvelle position de ton rayon est en dehors des objets de ta scène. Après, ça converge vers un epsilon. Naturellement. C'est fort. :)

Effectivement la différence avec le raycasting, c'est que tu ne calcules pas d'intersections, tu les approximes à un epsilon près. :)
Title: Re : Raymarching - besoin d'explications
Post by: nystep on 28 November 2010 à 11:06:36
Je conseille cet article, très bien fait:

http://http.developer.nvidia.com/GPUGems2/gpugems2_chapter08.html (http://http.developer.nvidia.com/GPUGems2/gpugems2_chapter08.html)
Title: Re : Raymarching - besoin d'explications
Post by: xoofx on 28 November 2010 à 11:20:03
Comme l'a souligné Patapom, le papier d'iq est une référence et aussi celui de gpugems par nystep ;)

J'avais contribué aussi à un petit article sur mon blog intitulé "Potatro, RayMarching and DistanceFields : a story of SphereTracing" (http://code4k.blogspot.com/2009/10/potatro-and-raymarching-story-of.html), plutôt simple et didactique, avec en prime une version 2D du raymarching pour comprendre comment cela ça fonctionne.... surtout lorsque l'on connait un peu le raytracing/casting mais qu'on ne voit pas la différence avec le raymarching.

D'où ma question : qu'est-ce que le "raymarching" apporte ? Ca sert à quoi de découper la recherche itérativement, et surtout est-ce que ça garantit qu'on trouve à coup sûr l'objet le plus proche sans le rater ? C'est quoi la théorie derrière ?
Le raymarching apporte la possibilité de rendre des formes qui sont souvent quasi-impossible à résoudre mathématiquement, de faire des combinaisons entre elles, sans que cela change quoi que ce soit au rendu... Essentiellement utilisé pour faire du rendu d'iso-surface. Après, pour déterminer l'intersection ("root finding") de manière itérative tu as plusieurs méthodes, dont la plus connue est "SphereTracing" de J.Hart... qui peut se coupler avec un algo de bisection basique sur les dernières itérations.
Title: Re : Raymarching - besoin d'explications
Post by: nystep on 28 November 2010 à 11:31:24
Quote
Ca se fait en un seul coup, pas de méthode itérative. Tu choisiras finalement le point le plus proche parmi les intersections avec tous les objets (ie la valeur t positive la plus faible). Il y a des algos pour éviter de calculer les intersections avec tous les objets de la scène.

Tu oublies juste un détail: un objet en raytracing, c'est un triangle. ;)

70 000 triangles c'est beaucoup. La structure d'accélération arborescente est énorme, et la parcourir fait plein d'accès mémoire aléatoires. De plus, construire une bonne structure d'accélération peut être très couteux, ce qui empêche de le faire pour les objets animés.
Title: Re : Raymarching - besoin d'explications
Post by: xoofx on 28 November 2010 à 11:47:50
La boucle de raymarching converge en général après 32-64 itérations, franchement c'est compétitif, surtout quand les accès mémoires sont cohérents avec les pixels adjacents... Il est également possible de faire du raymarching de façon hiérarchique: en faisant d'abord une approximation pour 16*16 pixels, puis 8*8, puis 4*4, puis 2*2 et enfin les pixels finaux... Là, tu tombes à 10 (ou -) évaluations de la fonction de distance par pixel..
J'avais tenté ça pour l'intro ergon 4k, mais j'avais été assez déçu... enfin, surtout dans le ratio quantité_de_code_supplémentaire / gain_en_perf. Bon, en plus, le problème avec ce système, c'est que tu peux te retrouver à avoir des "trous", ce qui fait que tu dois réduire le pas de manière empirique, suivant la scène, afin d'éviter ça...

Sinon, pour accélérer les choses, il y a aussi l'intérêt de faire du LOD sur la forme iso, surtout si par exemple la forme iso utilise des textures pour bumper les surfaces, il vaut mieux avoir une formule iso sans bumping, et intégrer le bumping sur les dernière itérations... c'est beaucoup moins couteux et pour le coup, ça aide pas mal dans les perfs.
Title: Re : Re : Raymarching - besoin d'explications
Post by: zerkman on 28 November 2010 à 12:36:59
Tu oublies juste un détail: un objet en raytracing, c'est un triangle. ;)

Bin dans mon exemple, j'ai donné des sphères comme objets possibles. Comme autres trucs simples il y a les parallélépipèdes (pas forcément rectangles et donc pas forcément des cubes), les cylindres, cones, plans, et compositions de tous ces trucs (unions / intersections). Les metaballs ou blobs ne sont pas compliqués non plus, c'est une fonction de distance par rapport à plusieurs centres de sphères au lieu d'un seul, les vecteurs normaux sont hyper faciles à calculer, etc.

Pour les triangles je suis parfaitement conscient que ça finit vite par devenir le bordel. L'idée est quand même de triangulariser au minimum, donc tout ce qui est faisable sans triangles doit être fait sans. En plus les triangles ont la facheuse tendance à bouffer de la mémoire, et il y a des plate-formes où la place mémoire est critique (ex. j'ai fait des trucs sur PS3 où chaque coeur dispose de 256 ko de ram).

70 000 triangles c'est beaucoup. La structure d'accélération arborescente est énorme, et la parcourir fait plein d'accès mémoire aléatoires. C'est inefficace: j'ai essayé.
En fait ça dépend énormément de ta structure d'accélération et de son organisation : par ex pour un kd tree, selon si l'arbre est équilibré, a une profondeur optimisée, etc, les résultats changent du tout au tout.

Et je maintiens qu'utiliser des triangles pour faire du raytracing, ça doit rester vraiment quand il n'y a pas d'autre solution.
Title: Re : Raymarching - besoin d'explications
Post by: TarMil on 28 November 2010 à 13:31:57
Pour résumer la différence:

Mais du coup, je dis peut-être une grosse connerie, mais est-ce qu'on ne pourrait pas raycaster les objets constructifs, raymarcher les objets implicites, pour finalement prendre le plus proche des deux ?
Title: Re : Raymarching - besoin d'explications
Post by: xoofx on 28 November 2010 à 14:48:50
Bin dans mon exemple, j'ai donné des sphères comme objets possibles. Comme autres trucs simples il y a les parallélépipèdes (pas forcément rectangles et donc pas forcément des cubes), les cylindres, cones, plans, et compositions de tous ces trucs (unions / intersections).
Je doute que tu puisses calculer des intersections facilement en appliquant des déformations (twist, shear...etc.) sur les formes iso comme ça se fait couramment lorsqu'on les utilise, non? Si cette technique de raymarching a été inventé (et ça date de 1989 quand même), c'est justement pour couvrir des cas ou le raycasting est inefficace...
Title: Re : Raymarching - besoin d'explications
Post by: nystep on 28 November 2010 à 16:38:26
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.
C'est important de définir la "distance intérieure" (négative) sinon la méthode des différences centrées pour calculer le gradient ne marche pas (artéfacts dans le calcul des normales dans ce cas)...
Title: Re : Raymarching - besoin d'explications
Post by: nystep on 28 November 2010 à 16:41:08
C'est également vrai que tu peux interopérer les 2 méthodes: il suffit de prendre le min des deux... l'interopérabilité marche y compris avec la rasterisation classique si tu prends soin d'écrire le zbuffer quand tu utilises le raytracing/raymarching
Title: Re : Raymarching - besoin d'explications
Post by: ntsc on 28 November 2010 à 17:19:14
tiens tite question..de graphiste :) c'est possible d'intégrer une scene en raymarching dans une scene 3D classique ?
PAr exemple une piece en 3D faite sous 3Ds et a l'interieur on lui colle un un truc tout space en raymarching ( comme dans la 4ko ergon).
Title: Re : Raymarching - besoin d'explications
Post by: ponce on 28 November 2010 à 18:15:08
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
Title: Re : Raymarching - besoin d'explications
Post by: flure on 28 November 2010 à 18:16:26
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 ;)
Code: [Select]
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;
}
Title: Re : Raymarching - besoin d'explications
Post by: TarMil on 28 November 2010 à 18:28:47
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
Title: Re : Raymarching - besoin d'explications
Post by: LittleWhite on 28 November 2010 à 18:38:23
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 ?
Title: Re : Re : Raymarching - besoin d'explications
Post by: Patapom on 28 November 2010 à 18:43:38
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 :

Code: [Select]
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 ?
Title: Re : Raymarching - besoin d'explications
Post by: flure on 28 November 2010 à 23:26:21
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é ?
Title: Re : Raymarching - besoin d'explications
Post by: TarMil on 28 November 2010 à 23:48:36
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.
Title: Re : Raymarching - besoin d'explications
Post by: Patapom on 29 November 2010 à 01:49:58
Flure (et les autres) ! On vient de me faire découvrir : http://www.iquilezles.org/apps/shadertoy/ (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)
Title: Re : Raymarching - besoin d'explications
Post by: nystep on 29 November 2010 à 05:22:51
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é..
Title: Re : Raymarching - besoin d'explications
Post by: flure on 29 November 2010 à 12:30:23
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 ;)
Title: Re : Raymarching - besoin d'explications
Post by: Patapom on 29 November 2010 à 12:35:07
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 !
Title: Re : Raymarching - besoin d'explications
Post by: Patapom on 29 November 2010 à 12:46:06
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 ?
Title: Re : Raymarching - besoin d'explications
Post by: nystep on 29 November 2010 à 17:28:37
oui, exact, bien vu :)
Title: Re : Raymarching - besoin d'explications
Post by: xoofx on 29 November 2010 à 18:28:30
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? (http://www.pouet.net/topic.php?which=6675&page=1&x=25&y=6), ainsi que  trick for 1k raymarchers :: lighting (http://www.pouet.net/topic.php?which=7535&page=1&x=24&y=8) et un thread + noob Problem with RayMarching using DistanceFunctions when applying Twist-Distortion. (http://www.pouet.net/topic.php?which=6803&page=1&x=14&y=8)
Title: Re : Raymarching - besoin d'explications
Post by: flure on 29 November 2010 à 21:46:22
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
Title: Re : Raymarching - besoin d'explications
Post by: flure on 29 November 2010 à 22:26:30
Bon, ben j'ai trouvé. Vous allez vraiment être atterrés...
Voilà le code d'origine :
Code: [Select]
float sphereDist(vec3 pos, vec3 center, float radius)
{
return length(center - pos) - radius;
}

et comme ça ça marche beaucoup mieux :
Code: [Select]
float sphereDist(vec3 pos, vec3 center, float radius)
{
return abs(length(center - pos) - radius);
}

Voilà, je suis un sacré boulet ;)
Title: Re : Raymarching - besoin d'explications
Post by: Patapom on 29 November 2010 à 22:49:18
Bon, ben j'ai trouvé. Vous allez vraiment être atterrés...
Voilà le code d'origine :
Code: [Select]
float sphereDist(vec3 pos, vec3 center, float radius)
{
return length(center - pos) - radius;
}

et comme ça ça marche beaucoup mieux :
Code: [Select]
float sphereDist(vec3 pos, vec3 center, float radius)
{
return abs(length(center - pos) - radius);
}

Voilà, je suis un sacré boulet ;)

Heu non, je trouve pas que t'es un boulet. La première formule était la bonne : il te faut des distances négatives quand t'es à l'intérieur de la sphère hein !
Ton problème se trouve ailleurs.
Title: Re : Raymarching - besoin d'explications
Post by: nystep on 30 November 2010 à 08:08:27
comme dit patapom la première formule est la bonne, mais sinon tu fais bien la valeur absolue de ta normale après l'avoir normalisée pour l'afficher ou bien... ;)

abs(normalize(n)) genre? :) sinon oui si elle est négative il la clampe à zéro et ça fait du noir ;)
Title: Re : Raymarching - besoin d'explications
Post by: nystep on 30 November 2010 à 08:11:20
   cc = dot(n, eye);

eye est une position, ce n'est pas un vecteur... il faut construire le vecteur et le normaliser, sinon ton lighting lambertien ne risque pas d'être correct ;)
Title: Re : Raymarching - besoin d'explications
Post by: flure on 30 November 2010 à 09:08:12
Ouaip mais pour eye j'ai mis en dur vec3(0, 0, 1) donc je pense que c'est normalisé ;)

Title: Re : Raymarching - besoin d'explications
Post by: flure on 30 November 2010 à 09:15:22
Heu non, je trouve pas que t'es un boulet. La première formule était la bonne : il te faut des distances négatives quand t'es à l'intérieur de la sphère hein !
Ton problème se trouve ailleurs.

Zut alors j'étais dans ma sphère noire. Donc je me suis perdu dans mon système de coordonnées. Si je commence à pas comprendre à ce point là déjà dès le début, je suis mal barré ;)
Title: Re : Raymarching - besoin d'explications
Post by: Patapom on 30 November 2010 à 14:01:15
Normalement le gradient est partout non nul avec tes 2 sphères, sauf sur le plan équidistant entre les 2 sphères... Je comprends même pas comment tu peux avoir du noir.
Tu peux reposter la dernière version du code entier steuplé ? Je le testerai chez moi.
Title: Re : Raymarching - besoin d'explications
Post by: flure on 30 November 2010 à 14:22:22
Ok je te poste ça ce soir après nettoyage ;)
Title: Re : Raymarching - besoin d'explications
Post by: flure on 30 November 2010 à 20:29:52
Euuuuh, je vais avoir l'air stupide mais je crois que mon problème a disparu. Sans doute que j'avais commencé d'une très mauvaise manière et qu'à force de suivre tes conseils j'ai résolu le problème sans m'en rendre compte (j'avais reculé la sphère concernée pour ne plus voir la sphère noire).

Enfin, je poste quand même ici le shader si jamais tu trouves des choses à y redire je suis preneur ;)
Le vertex shader bien cracra (oui oui la position de la caméra est en dur) :
Code: [Select]
varying vec3 eye, dir;

void main()
{
gl_Position = gl_Vertex;

eye = vec3(0, 0, 1);
dir = vec3(gl_Vertex) - eye;
}

Et le code du pixel shader :
Code: [Select]
varying vec3 eye, dir;

float maxDist = 10.0;
int maxNbStep = 64;
float eps = 0.005;
float n_eps = 0.00001;

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

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

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


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

for(steps = 0; steps < maxNbStep; steps++)
{
if(stepped > maxDist) break;

dt = dn * stepped;
d = distanceFunc(dt);
if(d < eps)
{
vec3 n = grad(dt);
cc = dot(n, eye);
gl_FragColor = vec4(cc, cc, cc, 1);
return;
}
stepped += d;
}
gl_FragColor = c;
}

Il faut savoir que je n'ai qu'une GeForce 7300 Go, et avec ces trois pauvres sphères, j'atteins les performances magnifiques de... 3fps...
Title: Re : Raymarching - besoin d'explications
Post by: flure on 30 November 2010 à 20:33:54
Une question qui me taraude, concernant le premier step du rayon : faut-il prendre en compte la distance déjà parcourue de la caméra à l'écran ? J'ai fait quelques essais pas concluants, donc je me demande si la question est pertinente...

Ah et il n'y a pas de notion de fov dans mon shader parce que j'ai créé une fenêtre carrée pour pas m'embêter avec ça ;)
Title: Re : Raymarching - besoin d'explications
Post by: flure on 01 December 2010 à 22:21:48
Bon ben j'ai un petit peu avancé je suis bien content, j'ai un truc qui ressemble à des metaballs :D (voir capture)
La formule de distance que j'utilise est celle-ci :
Code: [Select]
float distanceFunc(vec3 pos)
{
float r = 0.28;
float s1 = sphereDist(pos, vec3(0.3, 0.2, -0.8), r);
float s2 = sphereDist(pos, vec3(-0.3, 0.2, -0.8), r);
float s0 = (s1 * s2) * r;
return s0;
}

Je me doute bien que ça ne doit pas être la vraie formule des metaballs, mais le résultat y ressemble :) (au fait c'est quoi la vraie fonction de distance pour les metaballs ? :D)
Title: Re : Raymarching - besoin d'explications
Post by: nystep on 03 December 2010 à 17:45:59
j'avoue que tu me bluffes pour ce coup là!

non ce n'est pas la vraie formule, mais pourtant tu arrives bien à avoir une liaison correcte entre tes "sphères".
voici la fonction typique, tu peux remplacer 1 par la taille que tu souhaites donner aux "sphères" aussi:

f(x,y,z) = 1 / (1 + (x − x0)2 + (y − y0)2 + (z − z0)2)

cette fonction est donc égale à 1 au centre de la métaball, et elle tend vers 0 à l'infini
ce n'est donc pas une distance, mais en ajoutant diverses balles comme ça tu obtiendras l'effet de metaball bien connu.
il faut choisir tout de même un seuil entre 0 et 1... 0.2 devrait bien marcher.

pour évaluer la distance (approximativement) à la racine d'une fonction f:

0.5 * f(x) * log(f(x)) / f'(x) marche assez bien comme évaluateur... (seulement pour la distance extérieure quand f(x) > 0 à cause du logarithme)...

j'ai jamais essayé sur des fonctions dans le cas général, mais ça a l'air de bien marcher pour le mandelbulb...
Title: Re : Raymarching - besoin d'explications
Post by: flure on 03 December 2010 à 20:27:37
Merci bien Nystep !

J'avais trouvé une formule similaire la même formule sous cette forme : f(p) = R / length(centre - p)
Mais je n'arrivais pas à en déduire une fonction de distance. Parce que cette formule donne en fait l'énergie à un point  p dans le champ de la metaball, et nous il nous faut la distance à une "courbe de niveau de ce champ" en fait (je crois que ça je l'ai bien intégré ;)).

Enfin bref, je vais m'empresser de tester ta formule :D

Pour ma formule, je suis tombé dessus assez par hasard, mais elle ne me satisfait pas, elle est assez compliquée à maîtriser. Et puis ce que j'ai réussi à produire ne ressemble pas vraiment à des metaballs, même s'il y a continuité ;)
Title: Re : Raymarching - besoin d'explications
Post by: flure on 04 December 2010 à 18:48:20
Bon je continue avec mes aventures en raymarching.
J'essaye maintenant de faire des ombres projetées, et évidemment j'ai quelques petits soucis.
Comme vous le voyez sans doute, j'ai une ombre projetée correcte de ma sphère, mais j'ai plein d'artifacts sur les murs (et sur la sphère aussi d'ailleurs). On dirait que des zones qui ne devraient pas être ombrées le sont quand même.

Pour calculer si un pixel doit être ombré, je raymarche depuis la light vers la position que je veux ombrer. Si lors du raymarching je touche une surface avant d'arriver à la position, c'est donc qu'il doit être ombré. Je pense que mon problème est un problème de précision : quand le rayon de lumière est rasant par rapport à une surface, il détecte parfois un hit alors qu'il ne devrait pas. Je me trompe ?

Pour info voici la fonction qui me permet de savoir si on doit ombrer ou pas :
Code: [Select]
bool isLit(vec3 pos, vec3 light)
{
vec3 dt = light;
float l = length(light - pos);
vec3 r = normalize(pos - light);
float stepped = 0.0;
float d = MAX_DIST;

while((d > EPSILON) && (stepped < MAX_DIST))
{
dt = light + r * stepped;
d = distanceFunc(dt);
if(d < EPSILON) break;
stepped += d;
}

return abs(l - stepped) <= EPSILON;
}

La light est positionnée dans le coin supérieur droit de la box.

Voilà donc je pense qu'il faut que je trouve un moyen d'améliorer la précision de mes intersections évidemment. Mais si je diminue mon epsilon je me retrouve avec du noise, donc il va falloir que je trouve autre chose. Je vais sans doute creuser de ce côté : http://sizecoding.blogspot.com/2008/08/isosurfaces-in-glsl.html (http://sizecoding.blogspot.com/2008/08/isosurfaces-in-glsl.html)
Title: Re : Raymarching - besoin d'explications
Post by: Patapom on 04 December 2010 à 20:10:04
On dirait plutôt que tu as l'erreur typique du mec qui fait du ray-tracing pour la première fois ! ;D

Tu retournes à ton adolescence : tu as ce qu'on appelle "de l'acnée". Z-acnea...
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.

Essaye de faire :

pos += epsilon * normal

pour offseter ta position de départ en dehors du mur lors du premier step. Ca devrait résoudre ton problème...
Title: Re : Raymarching - besoin d'explications
Post by: flure 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) ;)
Title: Re : Raymarching - besoin d'explications
Post by: flure 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 !!!)
Title: Re : Raymarching - besoin d'explications
Post by: Patapom 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).
Title: Re : Raymarching - besoin d'explications
Post by: Patapom 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]
Title: Re : Raymarching - besoin d'explications
Post by: flure 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...
Title: Re : Raymarching - besoin d'explications
Post by: Patapom 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.
Title: Re : Raymarching - besoin d'explications
Post by: flure 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 ;)
Title: Re : Raymarching - besoin d'explications
Post by: Patapom 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 !
Title: Re : Raymarching - besoin d'explications
Post by: flure 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
Title: Re : Raymarching - besoin d'explications
Post by: RaHoW on 08 December 2010 à 12:37:56
Vas-y Flure, t'y es presque

(http://www.bible-topten.com/302.jpg)

^______________________-
Title: Re : Raymarching - besoin d'explications
Post by: Patapom 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 (http://mathinfo.ens.univ-reims.fr/IMG/pdf/hart94sphere.pdf) 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 (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...
Title: Re : Raymarching - besoin d'explications
Post by: xoofx 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 (http://www.pouet.net/topic.php?which=7236&page=1)", 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.
Title: Re : Raymarching - besoin d'explications
Post by: flure 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;
}
Title: Re : Raymarching - besoin d'explications
Post by: flure 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.
Title: Re : Raymarching - besoin d'explications
Post by: Elrick 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.
Title: Re : Raymarching - besoin d'explications
Post by: Patapom on 22 November 2011 à 23:46:00
Huhu, mais tu passes toujours le même rayon pour tous les pixels, comment veux-tu que ça marche ?
La position fixe, okay, mais tu peux pas passer le même "view".

Faut que t'écrives ça plutôt :
Code: [Select]
float4 raymarchingCast( float2 _UV )
{
       //c'est la que je force la position de la camera...
float3 p = float3( 0.0, 0.0, 0.0 ); //original pos of cam
float3 v = normalize( float3( 2.0 * _UV.x - 1.0, 1.0 - 2.0 * _UV.y, 1.0 ) ); // direction of cam

       // Ensuite, t'utilises (p,v) pour ray-marcher. Pas la peine d'utiliser des float4 partout, ça complique pour rien...
}
Et là, le paramètre UV c'est les coordonnées UV de ton quad. Ca devrait être (0,0) en haut à gauche de l'écran et (1,1) en bas à droite...

Sinon, essaie d'utiliser des swizzles et des vector operations dès que tu peux. Au lieu de :
Code: [Select]
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
);
}

Ecris plutôt (toujours avec des float3, sinon c'est chiant pour rien) :
Code: [Select]
float distanceToSphere( float3 center, float radius, float3 pos )
{
float3  Pos2Center = center - pos; // Là tu laisses le GPU traiter le float3, plutôt que faire les calculs sur chaque composante x,y,z
return length( Pos2Center ) - radius;  // length() fait exactement sqrt( x²+y²+z² ), pourquoi s'embêter ?
}

Et surtout ! Surtout ! Il vaut 100 fois mieux écrire x*x que pow( x, 2 ) !!!!! La première fait juste une multiplication, la seconde écriture fait appel à une fonction qu'est pas spécialement gratos...

Pareil, petite technique avec swizzle. Au lieu de :
Code: [Select]
color = float4(NdotL,NdotL,NdotL,1.0);

Ecris :
Code: [Select]
color = float4( NdotL.xxx, 1.0 );  // Un float est un vecteur particulier à une seule composante : x

Sinon, écrire :
Code: [Select]
float4 n = normalize(position);
Je sais vraiment pas ce que ça va faire ! Déjà il faut vraiment que "position" soit un float3, pas un float4, sinon tu normalises avec le w=1, ça va donner n'importe nawak. Pourquoi t'as choisi de foutre des float4 partout en fait, je comprends pas ?
Ensuite, comme expliqué un peu plus haut : tu essaies de normaliser une position, pas un vecteur. En l'occurence, tu dis : "prends la position où je touche la sphère et fais-en un vecteur". Ca va pas marcher.
Tu as une position, et tu cherches la normale. La normale est une direction. La différence entre position et direction est fondamentale ! Donc déjà, tu peux pas te servir d'une position comme direction. En fait, ça va marcher mais ça va te donner la direction [position - (0,0,0)] (depuis le centre du monde, là où t'as placé ta caméra, donc ça va donner une truc, mais cheulou (et en plus, dans ce cas, toujours négatif donc t'auras sans doute du noir. Prends la valeur absolue pour avoir qqchose).

Ce que tu veux c'est vraiment la normale à la surface à la position où t'as touché la sphère. Du coup, faut que t'utilises la routine de calcul de normale qu'est filée dans le papier d'iQ, je l'ai pas sous les yeux mais elle est assez facile à recopier. En ce qui concerne son fonctionnement, bah en gros ça va aller sampler le distance field partout autour de ta position en +X, -X, +Y, -Y, +Z et -Z et faire la différence entre toutes ces distances : ça te donne ce qu'on appelle un gradient. C'est la variation de distance en X, Y et Z autour de ton point. Et, magie, il se trouve que c'est également la direction de la normale de ta surface ! Tadaaaa !
Il faut donc que t'écrives :
Code: [Select]
float3  FonctionDeCalculDeNormaleRepompéeDansLeDocDiQ( float3 position )
{
  (...)
}

(...)
float3 n = FonctionDeCalculDeNormaleRepompéeDansLeDocDiQ(position);
float3 l = 1.0;
float NdotL = dot(n,l);
color = float4(NdotL.xxx,1.0);

Bon courage !
Title: Re : Raymarching - besoin d'explications
Post by: Elrick on 23 November 2011 à 06:58:02
Ha mais quel boulet je pensais pas que la "direction de la cam" c'était en fait le rayon qu'on lançait ... Effectivement vu comme ça je calcule tjrs le même pixel ...

Pour les "swizzles" (tiens j'ai appris un mot) et les pow, ok je vais faire plus attention à ce que j'écris :)

Pour les float4 heuu je sais pas parce que je trouvais que ça disait joli ? Non je maîtrise pas trop ce que j'ecris du coup j'ai même pas du réaliser que c'était une position. Effectivement c'est pas logique de mettre une position ds un float4 ...

Je vais reprendre ça ce soir je pense, merci en tt cas d'avoir pris le temps de m'expliquer tt ça.
Title: Re : Raymarching - besoin d'explications
Post by: xoofx on 23 November 2011 à 13:35:31
Et surtout ! Surtout ! Il vaut 100 fois mieux écrire x*x que pow( x, 2 ) !!!!! La première fait juste une multiplication, la seconde écriture fait appel à une fonction qu'est pas spécialement gratos...
Juste pour signaler que le compilo HLSL transforme un pow(x,2) en x*x. Je crois que ça marche même jusqu’à pow(x,8)! ;)
D'une manière générale, en HLSL, le code assembleur est très souvent super optimisé, donc il y a beaucoup moins de problèmes qu'avec des langages traditionnels. Mais bon, c'est aussi une bonne pratique que d'appliquer de facto ce que tu dis! :D (surtout par exemple en GLSL, car j'ai tendance a etre moins confiant sur les compilos GLSL).
Title: Re : Re : Raymarching - besoin d'explications
Post by: Patapom on 23 November 2011 à 14:27:05
Pour les "swizzles" (tiens j'ai appris un mot) et les pow, ok je vais faire plus attention à ce que j'écris :)
A noter que le swizzling marche aussi sur des constantes : t'as parfaitement le droit d'écrire float4( 1.0.xxx, 0.0 );

Juste pour signaler que le compilo HLSL transforme un pow(x,2) en x*x. Je crois que ça marche même jusqu’à pow(x,8)! ;)
D'une manière générale, en HLSL, le code assembleur est très souvent super optimisé, donc il y a beaucoup moins de problèmes qu'avec des langages traditionnels. Mais bon, c'est aussi une bonne pratique que d'appliquer de facto ce que tu dis! :D (surtout par exemple en GLSL, car j'ai tendance a etre moins confiant sur les compilos GLSL).
Hmm j'savais pas pour le compilo, moi de base je fais jamais confiance à une machine ! ;D Sinon c'est bien le Japon alors ?
Title: Re : Raymarching - besoin d'explications
Post by: Elrick on 24 November 2011 à 22:23:06
@patapom: je sais pkoi j'avais mis des float4, à cause de la def SV_POSITION tout au debut. du coup je suis obliger de laisser ca pour l'input et l'output du vertex shader non ?
bon sinon j'ai tjrs un ecran rouge ...
Title: Re : Raymarching - besoin d'explications
Post by: Patapom on 31 January 2012 à 13:36:03
Pour les fans de ray-marching dans un distance field, de nouvelles fonctions de distances pour calculer des knots et torus ainsi que des polyhèdres :

http://blog.hvidtfeldts.net/index.php/2012/01/knots-and-polyhedra/ (http://blog.hvidtfeldts.net/index.php/2012/01/knots-and-polyhedra/)

Ca va vous faire 3 ou 4 démos ça nan ? ;D
Title: Re : Raymarching - besoin d'explications
Post by: Saorel on 31 January 2012 à 20:09:17
Merci beaucoup Pata ! (Voire question posée avec le Loxo )
Title: Re : Re : Raymarching - besoin d'explications
Post by: Elrick on 14 February 2012 à 12:04:08
Pour les fans de ray-marching dans un distance field, de nouvelles fonctions de distances pour calculer des knots et torus ainsi que des polyhèdres :

http://blog.hvidtfeldts.net/index.php/2012/01/knots-and-polyhedra/ (http://blog.hvidtfeldts.net/index.php/2012/01/knots-and-polyhedra/)

Ca va vous faire 3 ou 4 démos ça nan ? ;D

miam !!
Title: Re : Raymarching - besoin d'explications
Post by: h0bby1 on 12 February 2013 à 19:58:27
http://www.youtube.com/watch?v=QfmCvGf2iQk# (http://www.youtube.com/watch?v=QfmCvGf2iQk#)

si yena que ca interresse toujours :) ya une version software avec du sse et ca c'est la version shader

bon ya encore du taf cela dit, ya quelque trucs qui sont pas encore top, mais ca commence a bien tourner, en sofware ca utilise le sse end multihread pour le multi core, ici sur un quadricore amd phantom can tourne a peu pres correct en 640x480, et la version shader est totalement fluide sur ati x7000, ca gere ombre reflection refraction et glow en software pour l'instant, si ca interresse je peux essayer de faire un tuto ou poster des sources mais c'est pas encore totalement op pour le moment :)
Title: Re : Raymarching - besoin d'explications
Post by: ponce on 13 February 2013 à 09:25:48
Ca m'intéresserait bien de voir tourner la version soft !
Title: Re : Raymarching - besoin d'explications
Post by: h0bby1 on 13 February 2013 à 11:03:33
ok, un exe pour tester, faut du sse et ca utilise 8 thread la, donc faut un multi core sse pour que ca tourne bien, ya principalement le test ray/bounding box qui est en sse, ya un systeme de pointer de fonction pour les fonctions sensibles, normalement ya moyen de detecter les features du cpu et utiliser une fonction sans sse si c'est pas present, et faudrai que le nombre de thread soit scalé de facon optimale en fonction du nombre de coeur et de l'hyperthreading, pour l'instant comme on dit chez nous 'ca marche chez moi' :D

je posterai des codes sources plus tard, pour l'instant je crois ya encore 2/3 trucs pas tout a fait correct dedans, j'aime mieux pas poster des truc avec des maths inccorects a part si ya des guru des matrices et d'algebre lineaires qui peuvent corriger lol mais bon je devrais arriver a debugger ca bientot

la version shader elle est un peu barbare aussi, le shader il met plusieurs dizaines de seconde a charger, je sais pas trop comment faire pour diminuer le temps de compilation/chargement d'un shader, doit il y avoir des astuces, mais une fois qu'il est chargé apres ca blinde =)


ca c'est le code du fragment shader, mais l'agorythm sofware ressemble a part le test sur les bounding box qui est plus optimisé dans la version software, c'est vraiment le bottle neck du rendu, le test ray/bbox est fait des dizaine de millions de fois par seconde, pour chaque pixel a tracer il doit tester toute les bounding box a chaque frame, plus les rayons refracté/reflechis, et la version software est recursive, en shader ya pas de recursion mais ca ressemble pas mal globalement


Code: [Select]

void main()
{
vec4 pix;
vec3 ray_origin;
vec3 origin;
vec3 ray_direction;
vec3 ray_inv_direction;
vec3 outPos;

vec3 normVec;
vec3 raypos,raydir;

int CastId;
int origId;
int n;



box_dets[0] =2;
box_dets[1] =0;
box_dets[2] =2;
box_dets[3] =0;
box_dets[4] =1;
box_dets[5] =1;

/*
box_ids[0] = ivec4(0,1,2,3);
box_ids[1] = ivec4(1,5,6,2);
box_ids[2] = ivec4(5,4,7,6);
box_ids[3] = ivec4(4,0,3,7);
box_ids[4] = ivec4(3,2,6,7);
box_ids[5] = ivec4(1,0,4,5);

cube_normz[0] = vec3(0.0,0.0,1.0);
cube_normz[1] = vec3(1.0,0.0,0.0);
cube_normz[2] = vec3(0.0,0.0,-1.0);
cube_normz[3] = vec3(-1.0,0.0,0.0);
cube_normz[4] = vec3(0.0,1.0,0.0);
cube_normz[5] = vec3(0.0,-1.0,0.0);
*/

//winW    = 1024.0;
//winH    = 768.0;


origin[0] =winW/2.0;
origin[1] =winH/2.0;
origin[2] =400.0;

raypos[0] =((float(gl_FragCoord.x)-winW/2.0)/winW)*100.0;
raypos[1] =((float(gl_FragCoord.y)-winH/2.0)/winH)*100.0;
raypos[2] =0.0;

raydir[0] =float(gl_FragCoord.x)-origin[0];
raydir[1] =float(gl_FragCoord.y)-origin[1];
raydir[2] =0.0-origin[2];

ray_origin = (raypos*cameraInvMat)+cameraPos;
ray_direction = normalize(raydir)*cameraInvNormal;

ray_inv_direction = 1.0/ray_direction;

D3_EPSILON = 0.000000000000001;
origId = 255;

if(castRay(ray_origin,ray_direction,ray_inv_direction,pix,outPos,normVec,origId)==1)
{
vec3 reflectedVec,refractedVec;
vec3 invReflect,invRefract;

vec3 newOut,newNorm;
vec4 reflPix,refrPix;
vec4 newPix;
vec4 pixNew;

float reflect_fac,refract_fac;
float shadow;
float light;
float len;

reflect_fac =0.2;
refract_fac =0.4;


reflectedVec = reflect (ray_direction,normVec);
refractedVec = refract (ray_direction,normVec,1.0,0.8);

invReflect = 1.0/reflectedVec;
invRefract = 1.0/refractedVec;


CastId = origId;
castRay (outPos,reflectedVec,invReflect,reflPix ,newOut,newNorm,CastId);


CastId = origId;
castRay (outPos,refractedVec,invRefract,refrPix ,newOut,newNorm,CastId);

pixNew =vec4(0.0,0.0,0.0,1.0);

pixNew[0] =pixNew[0]*(1.0-reflect_fac)+reflPix[0]*reflect_fac;
pixNew[1] =pixNew[1]*(1.0-reflect_fac)+reflPix[1]*reflect_fac;
pixNew[2] =pixNew[2]*(1.0-reflect_fac)+reflPix[2]*reflect_fac;

pixNew[0] =pixNew[0]*(1.0-refract_fac)+refrPix[0]*refract_fac;
pixNew[1] =pixNew[1]*(1.0-refract_fac)+refrPix[1]*refract_fac;
pixNew[2] =pixNew[2]*(1.0-refract_fac)+refrPix[2]*refract_fac;

shadow =1.0;

if(castRaytoLight(outPos,lightPos,origId)==1)
shadow*=0.5;


pix =pix*(shadow)+pixNew;

}


    gl_FragColor = pix;


}





et ca c'est pour charger les donnée a partir du programme principale



Code: [Select]


int CScene::getGeomData()
{
int dataStart;
int n;
dataStart=0;
n=0;
while(n<n_boxf)
{
boxData[dataStart+0] = box_testf[n]._parameters[0];
boxData[dataStart+1] = box_testf[n]._parameters[1];
boxData[dataStart+2] = box_testf[n]._parameters[4];

boxData[dataStart+3] = box_testf[n]._parameters[2];
boxData[dataStart+4] = box_testf[n]._parameters[3];
boxData[dataStart+5] = box_testf[n]._parameters[5];

dataStart += 6;

n++;
}

n=0;
while(n<CubefList->num_item)
{
cubef_t *cube;

cube = CubefList->getItemAt(n);

boxData[dataStart+0] = cube->center[0];
boxData[dataStart+1] = cube->center[1];
boxData[dataStart+2] = cube->center[2];

boxData[dataStart+3] = cube->size[0];
boxData[dataStart+4] = cube->size[1];
boxData[dataStart+5] = cube->size[2];

dataStart += 6;

boxData[dataStart+0] = cube->AABOX.cast_id-1;
boxData[dataStart+1] = cube->material.tid;

dataStart += 3;

transpose_mat3x3(cube->matrix,&boxData[dataStart+0]);

dataStart += 9;

n++;
}

n=0;
while(n<SpherefList->num_item)
{
spheref_t *sphere;

sphere = SpherefList->getItemAt(n);

boxData[dataStart+0] = sphere->center[0];
boxData[dataStart+1] = sphere->center[1];
boxData[dataStart+2] = sphere->center[2];

dataStart += 3;

boxData[dataStart+0] = sphere->AABOX.cast_id-1;
boxData[dataStart+1] = sphere->sq_radius;
dataStart += 3;


n++;
}

n=0;
while(n<CylfList->num_item)
{
cylf_t *cyl;

cyl = CylfList->getItemAt(n);

boxData[dataStart+0] = cyl->base[0];
boxData[dataStart+1] = cyl->base[1];
boxData[dataStart+2] = cyl->base[2];

dataStart += 3;


boxData[dataStart+0] = cyl->AABOX.cast_id-1;
boxData[dataStart+1] = cyl->radius;
boxData[dataStart+2] = cyl->height;
dataStart += 3;

boxData[dataStart+0] = cyl->material.tid;
boxData[dataStart+1] = cyl->material.reflect;
boxData[dataStart+2] = cyl->material.refract;
dataStart += 3;


transpose_mat3x3(cyl->inv_matrix ,&boxData[dataStart+0]);
dataStart += 9;

transpose_mat3x3(cyl->inv_norm_mat ,&boxData[dataStart+0]);

dataStart += 9;

transpose_mat3x3(cyl->norm_mat ,&boxData[dataStart+0]);
dataStart += 9;

n++;
}

return dataStart;
}




void copyBoxesToTex()
{
int n;
vec3f_t vec;
char UniformName[255];
float data;



BoxDataID = glGetUniformLocationARB (ProgramObject,"cubemap");
if(BoxDataID>=0)
glUniform1iARB (BoxDataID,0);

BoxDataID = glGetUniformLocationARB (ProgramObject,"boxDataTex");
if(BoxDataID>=0)
glUniform1iARB (BoxDataID,1);

BoxDataID = glGetUniformLocationARB (ProgramObject,"texture1");
if(BoxDataID>=0)
glUniform1iARB (BoxDataID,2);

BoxDataID = glGetUniformLocationARB (ProgramObject,"texture2");
if(BoxDataID>=0)
glUniform1iARB (BoxDataID,3);



data = winW;
  BoxDataID = glGetUniformLocationARB (ProgramObject,"winW");
if(BoxDataID>=0)
glUniform1fvARB (BoxDataID,1,&data);

data = winH;
BoxDataID = glGetUniformLocationARB (ProgramObject,"winH");
if(BoxDataID>=0)
glUniform1fvARB (BoxDataID,1,&data);


BoxDataID = glGetUniformLocationARB (ProgramObject,"lightPos");
if(BoxDataID>=0)
glUniform3fvARB (BoxDataID,1,Scene->lightPos);

BoxDataID = glGetUniformLocationARB (ProgramObject,"cameraInvNormal");
if(BoxDataID>=0)
glUniformMatrix3fv (BoxDataID,1,1,Scene->inv_matrice_normales);


BoxDataID = glGetUniformLocationARB (ProgramObject,"cameraInvMat");
if(BoxDataID>=0)
glUniformMatrix3fv (BoxDataID,1,1,Scene->inv_matrice);


BoxDataID = glGetUniformLocationARB (ProgramObject,"cameraPos");
if(BoxDataID>=0)
glUniform3fvARB (BoxDataID,1,Scene->camPos);


n=0;
while(n<6)
{
BoxDataID = glGetUniformLocationARB (ProgramObject,"cube_normz[0]");
if(BoxDataID>=0)
glUniform3fvARB (BoxDataID+n,1,cube_norm[n]);
n++;
}

BoxDataID = glGetUniformLocationARB (ProgramObject,"numboxes");
glUniform1iARB (BoxDataID,Scene->n_boxf);

BoxDataID = glGetUniformLocationARB (ProgramObject,"num_cubes");
if(BoxDataID>=0)
glUniform1iARB (BoxDataID,Scene->CubefList->num_item);

BoxDataID = glGetUniformLocationARB (ProgramObject,"num_spheres");
if(BoxDataID>=0)
glUniform1iARB (BoxDataID,Scene->SpherefList->num_item);


BoxDataID = glGetUniformLocationARB (ProgramObject,"num_cyls");
if(BoxDataID>=0)
glUniform1iARB (BoxDataID,Scene->CylfList->num_item);

Scene->getGeomData ();

glEnable (GL_TEXTURE_1D);
glBindTexture (GL_TEXTURE_1D, boxDataTexId);
glTexSubImage1D (GL_TEXTURE_1D,0,0,1024,GL_RGB,GL_FLOAT,Scene->boxData );
glBindTexture (GL_TEXTURE_1D, 0);
glDisable (GL_TEXTURE_1D);
}



///---------------------
///affichage

Scene->setSphereCenterf (spheref, (cosf((float)(Scene->cur_time)/2000.0f))*400.0f+400.0f,200.0f,(-sinf((float)(Scene->cur_time)/2000.0f))*500.0f+600.0f);
Scene->setCubeCenterf (cubef ,(sinf((float)(Scene->cur_time)/2000.0f))*250.0f+300.0f,350.0f,(-cosf((float)(Scene->cur_time)/2000.0f))*500.0f+800.0f,Scene->cur_time/400000.0,Scene->cur_time/800000.0,0);
Scene->setCylCenterf (cylf ,cylf->base[0],cylf->base[1],cylf->base[2],Scene->cur_time/400000.0,Scene->cur_time/800000.0,0);

if(ProgramObject)
{
//box_testf[n]._parameters

copyBoxesToTex ();

glActiveTextureARB (GL_TEXTURE0);
glEnable (GL_TEXTURE_2D);
glEnable (GL_TEXTURE_CUBE_MAP_ARB);
glBindTexture (GL_TEXTURE_CUBE_MAP_ARB, cube_map_texture_ID);

glActiveTextureARB (GL_TEXTURE1);
glEnable (GL_TEXTURE_1D);
glBindTexture (GL_TEXTURE_1D, boxDataTexId);

glActiveTextureARB (GL_TEXTURE2);
glEnable (GL_TEXTURE_2D);
glBindTexture (GL_TEXTURE_2D, glTexId);


glUseProgramObjectARB (ProgramObject);

}
else
{
n=0;
while(n<n_threads)
{
SetEvent (thread[n].EventStart);
Events[n]=thread[n].EventFinish;
n++;
}
WaitForMultipleObjects(n_threads,Events,TRUE,INFINITE);

glActiveTextureARB (GL_TEXTURE0);
glDisable (GL_TEXTURE_CUBE_MAP_ARB);

glEnable (GL_TEXTURE_2D);
glBindTexture (GL_TEXTURE_2D, texId);
glTexSubImage2D (GL_TEXTURE_2D,0,0,0,winW,winH,GL_RGB,GL_UNSIGNED_BYTE,Scene->texData);
}

Scene->frame++;

glLoadIdentity (); // Reset The Current Modelview Matrix
glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear Screen And Depth Buffer
glColor3f (1,1,1);



glBegin (GL_QUADS);

glTexCoord2f(0,0);
glVertex2f(-1.0f,-1.0f);

glTexCoord2f(0,winH/1024.0f);
glVertex2f(-1.0f,1.0f);

glTexCoord2f(winW/1024.0f,winH/1024.0f);
glVertex2f(1.0f,1.0f);

glTexCoord2f(winW/1024.0f,0);
glVertex2f(1.0f,-1.0f);
glEnd();


la fonction threadée est comme ca :

Code: [Select]
DWORD WINAPI doCasts(LPVOID tp)
{


unsigned int pX,pY;
unsigned int n;
unsigned int idx;
unsigned char *pData;
thread_info_t *t;
rayf_t *new_ray;


t = (thread_info_t *)tp;
new_ray = (rayf_t *)aligned_alloc(sizeof(rayf_t));


while(t->threadSync!=0)
{
WaitForSingleObject (t->EventStart,INFINITE);
pY = t->sY;
while(pY<t->eY)
{
pX = t->sX;
n = pY*winW+pX;
pData = &Scene->texData[n*3];
while(pX<t->eX)
{
vec3f_t ray_origin,ray_direction;
vec3f_t o;



mul_vec3x3_o (raysf[n].origin ,Scene->inv_matrice ,ray_origin);
mul_vec3x3_o (raysf[n].direction ,Scene->inv_matrice_normales ,ray_direction);

ray_origin[0] =ray_origin[0]+Scene->camPos[0];
ray_origin[1] =ray_origin[1]+Scene->camPos[1];
ray_origin[2] =ray_origin[2]+Scene->camPos[2];

init_rayf (new_ray,ray_origin,ray_direction);

castRayf (new_ray,pData,0,t->reflectRayf);

n++;

pData+=3;
pX++;
}
pY++;
}
SetEvent(t->EventFinish);

}
return NULL;
}


la fonction castray est similaire a celle du shader
Title: Re : Raymarching - besoin d'explications
Post by: Elrick on 22 May 2013 à 11:10:40
Need help !!
la j'ai vraiment l'impression d'être un singe en train d'essayer de comprendre pourquoi la forme carrée entre pas dans le trou triangulaire ...

en gros je tests un peu tout les bouts de codes qu'il y a sur pouet (le thread raymarching beginners) et la plupart du temps ... ca marche pas :/

un exemple en particulier, la spikeball, la fonction proposée sur pouet est la suivante:
Code: [Select]
float2 res; // Widht/Height
float t; // Time

float3 c[19]={
{1,0,0},{0,1,0},{0,0,1},
{.577,.577,.577},{-.577,.577,.577},
{.577,-.577,.577},{.577,.577,-.577},{0,.357,.934},
{0,-.357,.934},{.934,0,.357},{-.934,0,.357},
{.357,.934,0},{-.357,.934,0},{0,.851,.526},
{0,-.851,.526},{.526,0,.851},{-.526,0,.851},
{.851,.526,0},{-.851,.526,0}};

float spikeball(float3 p){
  float l = length(p);
  p = normalize(p);
  float b=0;
  for (int i=3;i<19;i++)
    b=max(abs(dot(p,c[i])),b);
  b=1-acos(b-.01)/(acos(-1)/2); 
  b=smoothstep(.78,1,b);
  return l-2.2*pow(1.5,b*(1.-lerp(.1,2,sin(t+t)*.5+.5)*b));
}

// Rotation
#define R(p, a) p=cos(a)*p+sin(a)*float2(p.y,-p.x)

float f(float3 p){
  p.z+=10.;
  p.y+=.5;
  float3 q=p;
  R(p.yz,t);
  R(p.xz,t+t+p.x*sin(t)*0.2);
  float d = spikeball(p);
  float nd = dot(q+float3(0.,3., 0.), float3(0., 1.,0.));
  return min(nd,d)*0.8;
}

float as(float3 p, float3 n, float d, float i){
  float s=sign(d);
  float o=s*.5+.5;
  for(;i>0;--i)
    o-=(i*d - f(p+n*i*d*s))/exp2(i);
  return saturate(o);
}

float4 main(float2 v:TEXCOORD):COLOR{
  // p: Position / d: Direction
  float3 p=float3(0,0,3);
  float3 d=float3(v*float2(res.x/res.y,1), 0) - p;
  d=normalize(d);
 
  // Raymarching loop
  float i, r, l, a, s, ml=.001;
  for (i=0; i<1; i+=1/64.){
    l = f(p);
    p += l*d;
    l = abs(l);
    r += l;
    if (l < ml*r) break;
  }   

  // Compute normal
  float2 epsilon = {.01,0};
  float3 n=normalize(
    float3(
      f(p+epsilon.xyy) - f(p-epsilon.xyy),
      f(p+epsilon.yxy) - f(p-epsilon.yxy),
      f(p+epsilon.yyx) - f(p-epsilon.yyx)
      )
    );

  return max(1+dot(n,d),0);
}

ma version
Code: [Select]
#define MAX_DISTANCE 200.0f
#define MAX_ITERATIONS 64.0f
#define EPSILON 0.0002f

cbuffer cbRender : register( b0 )
{
float4 _params; //W,H,_near,_far
matrix _camera2World;
matrix _world2Camera;
matrix _camera2Proj;
matrix _proj2Camera;
matrix _world2Proj;
matrix _proj2World;
};

cbuffer cbRender : register( b1 )
{
float4 _time;
float4 _resolution;
};

cbuffer cbTweaks : register( b2 )
{
float4 _a; //x = aofactor
float4 _lightColor;
float3 _pos;
};


float3 c[19]=
{
{1,0,0},{0,1,0},{0,0,1},
{.577,.577,.577},{-.577,.577,.577},{.577,-.577,.577},
{.577,.577,-.577},{0,.357,.934},{0,-.357,.934},
{.934,0,.357},{-.934,0,.357},{.357,.934,0},
{-.357,.934,0},{0,.851,.526},{0,-.851,.526},
{.526,0,.851},{-.526,0,.851},{.851,.526,0},
{-.851,.526,0}
};

float spikeball(float3 p)
{
float l = length(p);
p = normalize(p);
float b = 0;
for (int i=3; i<19; i++)
b=max(abs(dot(p, c[i])), b);
b=1 - acos(b - .01)/(acos(-1) * .5);
b=smoothstep(.78, 1, b);
return l-2.2*pow(1.5,b*(1.-lerp(.1,2,sin(_time.x*2)*.5+.5)*b));
}

float DistanceToScene(float3 _position)
{
return spikeball(_position);
}

float3 NormalAtPoint(float3 _position)
{
float3 normal = (float3)0;
float3 offset = float3 ( EPSILON, 0, 0 );
normal.x = DistanceToScene(_position+ offset.xyz) - DistanceToScene(_position-offset.xyz);
normal.y = DistanceToScene(_position+ offset.yxz) - DistanceToScene(_position-offset.yxz);
normal.z = DistanceToScene(_position+ offset.zxy) - DistanceToScene(_position-offset.yzx);

return normalize(normal);
}

float AoAtPoint( float3 _position, float3 _normal)
{

float total = .0f;
float weight = .5f;

[unroll]
for(int i=0;i<5;i++)
{
float delta = (i+1) * (i+1) * EPSILON * 12.0f;
total += weight * (delta - DistanceToScene( _position + _normal * delta));
weight *= .5f;
}

return 1.0f - saturate (total);
}

struct VS_IN
{
float4 _position : SV_POSITION;
};

struct PS_IN
{
float4 _position : SV_POSITION;

};

PS_IN VS(VS_IN VsIn)
{
PS_IN psin = (PS_IN)0;
psin._position = VsIn._position;
return psin;
}

float4 PS(PS_IN _in): SV_TARGET0
{
float2 p = -1.0f + 2.0f * _in._position.xy / _resolution.xy;
p.x *= _resolution.x/_resolution.y;
float3 camPos = _pos;
float3 rayPos = camPos;
float3 rayDir = normalize(float3(p,1.0f)); //TODO recalculer correctement le FOV focé a 90°

float3 lightDir = float3(cos(_time.x),-1.0f,0.0f);
float3 lightColor = float3 ( 1.0f, 0.9f, 0.7f );

float totalDistance = 0.0f;
int totalIterations = 0;

float3 color = float3(.6f,.6f,.6f);

for(float iter=0; iter<MAX_ITERATIONS && totalDistance < MAX_DISTANCE; iter++)
{
float distance = DistanceToScene(rayPos);

if (distance < EPSILON)
{
break;
}
rayPos += rayDir * distance;
totalDistance += distance;
}

if (totalDistance >= MAX_DISTANCE)
{
return float4(.0f,.0f,.0f,1.0f);
}
color= float3(1.0f,.7f,.4f);
float3 normal = NormalAtPoint(rayPos);
float3 light = lightDir;
float3 V = normalize ( camPos - rayPos );
float3 H = normalize ( V + light );

float diffuse = saturate( dot( normal,light));
color = lerp(color,lightColor,diffuse);

float ao = AoAtPoint(rayPos, normal);
color = lerp(float3(.0f,.0f,.0f),color,ao);

float specularTerm = saturate ( pow ( saturate ( dot ( normal, H ) ), 512 ) );
color += lightColor * specularTerm * ao;

return float4(color,1.0f);
}

et ce que j'ai a l'écran est une belle sphere bien ronde !!! (en pièce jointe).

qu'est ce que je fais pas correctement ?

Title: Re : Raymarching - besoin d'explications
Post by: Patapom on 23 May 2013 à 17:46:13
Tiens je t'ai refais un code que tu peux mettre directement dans shader toy pour essayer :

Code: [Select]
#define t iGlobalTime

float spikeball(vec3 p, vec3 v)
{
vec3 c[19];
c[0] = vec3(1,0,0);
c[1] = vec3(0,1,0);
c[2] = vec3(0,0,1);
c[3] = vec3(.577,.577,.577);
c[4] = vec3(-.577,.577,.577);
c[5] = vec3(.577,-.577,.577);
c[6] = vec3(.577,.577,-.577);
c[7] = vec3(0,.357,.934);
c[8] = vec3(0,-.357,.934);
c[9] = vec3(.934,0,.357);
c[10] = vec3(-.934,0,.357);
c[11] = vec3(.357,.934,0);
c[12] = vec3(-.357,.934,0);
c[13] = vec3(0,.851,.526);
c[14] = vec3(0,-.851,.526);
c[15] = vec3(.526,0,.851);
c[16] = vec3(-.526,0,.851);
c[17] = vec3(.851,.526,0);
c[18] = vec3(-.851,.526,0);

float MinDistance = 1e4;
for ( int i=3; i < 19; i++ )
{
float d = min( 1.0, abs( dot( p, c[i] ) ) );
#if 1
vec3 proj = sign( dot( p, c[i] ) ) * d * c[i];
#else
vec3 proj = d * c[i];  // Sans le sign ça donne un truc vraiment classe!
#endif
float Distance2Spike = length( p - proj );
float SpikeThickness = 0.25 * exp( -5.0*d ) + 0.0;
float Distance = Distance2Spike - SpikeThickness;

MinDistance = min( MinDistance, Distance );
}

return MinDistance;
}

// Rotation
#define R(p, a) p=cos(a)*p+sin(a)*vec2(p.y,-p.x)

float Distance( vec3 p, vec3 v )
{
// p.z += 10.0;
// p.y += 0.5;
vec3 q = p;
R( p.yz, t );
R( p.xz, 2.0*t + p.x*sin(t)*0.2 );
float d = spikeball(p, v);
return d;

float nd = dot( q + vec3(0.0,3.0, 0.0), vec3(0.0, 1.0,0.0));
return min( nd, d ) * 0.8;
}

void main(void)
{
vec2 uv = gl_FragCoord.xy / iResolution.xy;
vec3 p = vec3( 0, 0, 20 );
vec3 v = vec3( (2.0 * uv - 1.0) * vec2( iResolution.x / iResolution.y, 1 ), 0 ) - p;
v = normalize(v);
 
  // Raymarching loop
float i, r, l, a, s, ml=0.001;
for ( i=0.0; i<1.0; i += 1.0/64.0 ){
l = Distance(p, v);
p += l*v;
l = abs(l);
r += l;
if (l < ml*r) break;
  }   

  // Compute normal
  vec2 epsilon = vec2( 0.01,0.0 );
  vec3 n=normalize(
    vec3(
      Distance(p+epsilon.xyy, v) - Distance(p-epsilon.xyy, v),
      Distance(p+epsilon.yxy, v) - Distance(p-epsilon.yxy, v),
      Distance(p+epsilon.yyx, v) - Distance(p-epsilon.yyx, v)
      )
    );

  gl_FragColor = vec4( max(1.0+dot(n,v),0.0) );
}
Title: Re : Raymarching - besoin d'explications
Post by: Elrick on 24 May 2013 à 11:32:40
ha houais non mais j'ai pas ça du tout moi :/
c'est quoi encore ce bordel, ou j'ai merdé ....

ho put* je viens de me rendre compte que le tableau déclaré hors de la fonction faisait tt foiré, si je le déclare dans la fonction spikeball, ca "marche" mieux, quelqu'un peut m'expliquer ?

---
ha bah voila si je mets "static float3 c[19]={..." ca marche bcp mieux !!

on peut m'expliquer pkoi si je le mets pas le compilo gueule pas et le shader "utilise" je sais pas quelle valeurs ? (je suppose)
Title: Re : Raymarching - besoin d'explications
Post by: Patapom on 24 May 2013 à 16:45:38
'cune idée mais ouais normalement si tu déclares un tableau de constantes en HLSL en dehors du scope d'une fonction c'est static const devant. Là j'ai galéré en GLSL pour webgl car de toute manière ce genre de tableaux n'est pas supporté alors je l'ai rentré en dur dans la fonction, c'est crade mais ça marche.

Après j'ai bidouillé ma propre formule, je sais pas trop ce que le type fabrique avec ses acos() un peu plus loin, notamment son acos(-1) qui vaut PI en fait hein...
Bref, je pense que ce qui te manque principalement c'est la technique de débugging du shader : tu copicolles un code et tu t'attends à ce que ça marche. J'ai fait pareil dans shader toy et j'avais rien qui marchait, même pas une sphère donc j'étais au même point que toi mais ensuite j'ai viré tous les trucs un peu obscurs de la formule du gars et j'ai testé ligne à ligne en mettant des "return valeur" à chaque nouvelle ligne que je validais, pour vérifier mon code... (l'équivalent du débug au printf en fait)
Je pense pas que t'aies fait cette démarche, or c'est indispensable quand tu fais du shader de "sortir une valeur" dans le pixel qui te permet de vérifier chaque étape.

C'est plus difficile dans le cas du ray-marching car t'es à l'intérieur d'une boucle mais même tu peux te démerder pour avoir des valeurs de distance simples pour tester le bouzin pas à pas...

Title: Re : Raymarching - besoin d'explications
Post by: Hellflip on 25 May 2013 à 21:55:28
Originale comme forme de spikeball, les piques fins à fond, ca peux faire une bonne scène blood ! Chez moi ca donne ca (image attaché), rendu avec un petit exe homemade pour voir du quad shader.
Ca bug un peu, ya des points qui se baladent, mais ca c'est pas la premiere fois que je  vois des bugs de shaders glsl sur sur ma Radeon Mobility 5650. En utilisant "i += 1.0/32.0" (au lieu de 1.0/64.0) les petits points disparaissent, ca double le framerate, et visuellement on ne voit pas vraiment de différence.
Title: Re : Raymarching - besoin d'explications
Post by: Saorel on 02 July 2013 à 18:39:48
Yopla ( oui oui deterrage  8))

Bon je voulais finir un petit truc, et je me heurte à un petit problème.
L'idée est d'avoir 2 sphères de diametre 2.4 et 0.8, et respectivement de centre ( 0., 0., 0.) et (2.4, 0., 0.).
Je voudrais calculer la meta-surface reliant les 2. De mémoire je faisais distanceSphere1 * distanceSphere2 / (rayon1* rayon2) ;
Mais le résultat n'est pas probant du tout.

Code: [Select]
  for(int i = 0; i<64; i++)
  {
    vec3 c = ro + d *rd;
    float d1 = length(c)-2.4;
    float d2 = distance(c,vec3(2.,0.,0.))-.8;
    float e = min(d1,d2);
    if(e < .1)
    {
      color = vec3(1.,d1,d2);
    }
    d+=e;
  }

Du coup en l'etat je suis revenu sur un raymarcher avec 2 Spheres, mais j'ai vraiment besoin de la metasurface ;-)
Si quelqu'un peut me filer une piste pour la fonction distance à appliquer s'il vous plait ?

Merci beaucoup

S

P.S : j'ai bien vu le message de nystep 2 pages avant ( c'est d'ailleurs comme ca qu ej'ai trouvé le thread), sauf que j'ai du rater une marche...
Title: Re : Raymarching - besoin d'explications
Post by: Saorel on 03 July 2013 à 10:49:14
Etant donné que ca m'embeter legerement, je me suis dis que j'allais tenter un blending :

Code: [Select]
float smoothCurves(float x)
{
  return (x<0.)?0.:x;
}

void main()
{
  vec2 p = -1.0 + 2.0 * gl_FragCoord.xy / resolution.xy;
  p.x *= resolution.x/resolution.y;

  vec3 ro = ExtractCameraPos(modelViewMatrix);
  vec3 ww = normalize(vec3(0.0) - ro);
  vec3 uu = normalize(cross( vec3(0.0,1.0,0.0), ww ));
  vec3 vv = normalize(cross(ww,uu));
  vec3 rd = normalize( p.x*uu + p.y*vv + 1.5*ww );

  vec3 color = vec3(0.,.5,.5);
  float d =0.;

  for(int i = 0; i<64; i++)
  {
    vec3 c = ro + d *rd;
    float d1 = length(c)-1.2;
    float d2 = distance(c,vec3(1.2,0.,0.))-.4;
    float e = mix(d1,d2,smoothCurves(d1-d2));
    if(e < .01)
    {
      color = vec3(1.,d1,d2);
    }
    d+=e;
  }

  gl_FragColor = vec4(color, 1.0);
}

Sauf que la surface est toujours pas assez smooth ... Je vais y arriver, je vais y arriver !
Title: Re : Raymarching - besoin d'explications
Post by: Saorel on 03 July 2013 à 13:39:55
C'est mieux, mais c'est toujours pas ce qui m'interesse :

Code: [Select]
for(int i = 0; i<64; i++)
  {
    vec3 c = ro + d *rd;
    vec3 c1 = c;
    float mbd1 = 1.2/(1.2+dot(c1,c1));
    vec3 c2 = c-vec3(1.2,0.,0.);

    float mbd2 = .4/(.4+dot(c2,c2));
    float e = mbd1 + mbd2;
   
    if(e < .055 )
    {
      color = vec3(1.,mbd1,mbd2);
      break;
    }
    d+=e;
}

Grrr ... Tout ce que je souhaite, c'est relier 2 sphères avecune jolie enveloppe englobante  :-\ Ca va le faire ...
Title: Re : Raymarching - besoin d'explications
Post by: flure on 03 July 2013 à 14:23:29
Tu as essayé de faire simplement un blend des distances à tes deux sphères ? Une interpolation linéaire devrait déjà donner quelque chose. J'avais fait un truc dans le genre il y a quelques temps, je ne me souviens plus de la méthode (mais elle doit être dans ce thread). Ce n'était pas parfait, mais c'était un début...
Title: Re : Raymarching - besoin d'explications
Post by: Saorel on 03 July 2013 à 16:13:47
Ouep, justement (c'est en page 3) ^^ J'ai fait le test et c'est d'ailleurs c'est actuellement la meilleure solution.
Mais J'ai du raté quelque chose...  dans le sens ou la surface était pas assez ouverte à l'intersection. (trop angulaire)
Ca va bien finir par le faire  :o

Bilan, je me rapproche de ce que je veux, j'ai un peu triché mais bon ca devrait le faire. Aller plus qu'à réussir à faire un fake subsurface ...