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

0 Members and 1 Guest are viewing this topic.

Offline Patapom

  • Base
    • View Profile
    • www.patapom.com
  • Ancienneté: 1988
  • Groupe: Bomb!
  • Rôle: Coder
  • Ville: Lyon
Re : Raymarching - besoin d'explications
« Reply #60 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 !
.  Pom  .

Offline Elrick

  • Base
    • View Profile
  • Groupe: SFX
  • Rôle: Code / GFX
  • Ville: Lyon
Re : Raymarching - besoin d'explications
« Reply #61 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.

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 #62 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).

Offline Patapom

  • Base
    • View Profile
    • www.patapom.com
  • Ancienneté: 1988
  • Groupe: Bomb!
  • Rôle: Coder
  • Ville: Lyon
Re : Re : Raymarching - besoin d'explications
« Reply #63 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 ?
.  Pom  .

Offline Elrick

  • Base
    • View Profile
  • Groupe: SFX
  • Rôle: Code / GFX
  • Ville: Lyon
Re : Raymarching - besoin d'explications
« Reply #64 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 ...

Offline Patapom

  • Base
    • View Profile
    • www.patapom.com
  • Ancienneté: 1988
  • Groupe: Bomb!
  • Rôle: Coder
  • Ville: Lyon
Re : Raymarching - besoin d'explications
« Reply #65 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/

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

Offline Saorel

  • Base
    • Coup de coeur
    • View Profile
  • Ancienneté: 2010
  • Rôle: Kodeur
  • Ville: Nice
Re : Raymarching - besoin d'explications
« Reply #66 on: 31 January 2012 à 20:09:17 »
Merci beaucoup Pata ! (Voire question posée avec le Loxo )
" We are mutants. If we don’t deeply understand, if we don’t integrate that we are mutants, we completely miss the story " - One of the biggest designer of the World.

Offline Elrick

  • Base
    • View Profile
  • Groupe: SFX
  • Rôle: Code / GFX
  • Ville: Lyon
Re : Re : Raymarching - besoin d'explications
« Reply #67 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/

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

miam !!

Offline h0bby1

  • Base
    • View Profile
Re : Raymarching - besoin d'explications
« Reply #68 on: 12 February 2013 à 19:58:27 »
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 :)

Offline ponce

Re : Raymarching - besoin d'explications
« Reply #69 on: 13 February 2013 à 09:25:48 »
Ca m'intéresserait bien de voir tourner la version soft !

Offline h0bby1

  • Base
    • View Profile
Re : Raymarching - besoin d'explications
« Reply #70 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

Offline Elrick

  • Base
    • View Profile
  • Groupe: SFX
  • Rôle: Code / GFX
  • Ville: Lyon
Re : Raymarching - besoin d'explications
« Reply #71 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 ?


Offline Patapom

  • Base
    • View Profile
    • www.patapom.com
  • Ancienneté: 1988
  • Groupe: Bomb!
  • Rôle: Coder
  • Ville: Lyon
Re : Raymarching - besoin d'explications
« Reply #72 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) );
}
.  Pom  .

Offline Elrick

  • Base
    • View Profile
  • Groupe: SFX
  • Rôle: Code / GFX
  • Ville: Lyon
Re : Raymarching - besoin d'explications
« Reply #73 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)
« Last Edit: 24 May 2013 à 12:05:46 by Elrick »

Offline Patapom

  • Base
    • View Profile
    • www.patapom.com
  • Ancienneté: 1988
  • Groupe: Bomb!
  • Rôle: Coder
  • Ville: Lyon
Re : Raymarching - besoin d'explications
« Reply #74 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...

.  Pom  .