Фрагмент шейдера в raytracing показывает некоторые странные вещи - PullRequest
0 голосов
/ 09 февраля 2019

Я переехал в свое путешествие по трассировке лучей.Мне удалось визуализировать сетку с трассировкой лучей и рассчитать тени.Но когда я попытался сделать отражения и добавить отскоки, я получил абсолютно черный экран.Я очистил код и добавил комментарии, и мне кажется, что я нашел проблему в вычислениях, но не могу найти причину этого.

#version 300 es\n
precision highp float;
precision highp int;
precision highp sampler2D; 
in vec2 vuv;
uniform float time;
uniform vec2 Res, mouse;
uniform sampler2D uMeshData;
uniform int vertsCount;
uniform mat4 uRot;
layout(location = 0) out lowp vec4 fragColor;

#define MAX_BOUNCES 4
#define rmat(a, b) mat3(1, 0, 0, 0, cos(b), -sin(b), 0, sin(b), cos(b)) * mat3(cos(a), 0, sin(a), 0, 1, 0, -sin(a), 0, cos(a))

// Materials
#define LAMB 0
#define METAL 1
#define DIEL 2


struct Ray {
  vec3 orig, dir;
}R_;

struct Material
{
    int type;
    vec3 albedo; 
};

struct Sphere{
    vec3 center;
    float radius;
};

mat4 rotate() {
    // original x= mouse.x, y= mouse.y
    float x = mouse.y; //y=mouse.y+sin(time*2.),z=0.;
    float y= mouse.x,z=0.;
    float a = sin(x), b = cos(x), c = sin(y), d = cos(y), e = sin(z), f = cos(z), ac = a * c, bc = b * c;

    return mat4(d * f,           d * e,           -c,     0.0, 
                ac * f - b * e,  ac * e + b * f,  a * d,  0.0,     
                bc * f + a * e,  bc * e - a * f,  b * d,  0.0, 
                0.0,             0.0,             0.0,    1.0);
}

mat4 frotate( float x, float y, float z ){
    float a = sin(x); float b = cos(x); 
    float c = sin(y); float d = cos(y); 
    float e = sin(z); float f = cos(z); 

    float ac = a*c;
    float bc = b*c;

    return mat4( d*f,      d*e,       -c, 0.0,
                 ac*f-b*e, ac*e+b*f, a*d, 0.0,
                 bc*f+a*e, bc*e-a*f, b*d, 0.0,
                 0.0,      0.0,      0.0, 1.0 );
}

mat4 translate( float x, float y, float z ){
    return mat4( 1.0, 0.0, 0.0, 0.0,
                 0.0, 1.0, 0.0, 0.0,
                 0.0, 0.0, 1.0, 0.0,
                 x, y, z, 1.0 );
}


vec3 getHitPoint(Ray ray, float t) {
    return ray.orig + t * ray.dir;   
}

//intersection test with spheres
bool hitSphere(vec3 orig,vec3 dir,vec3 center,float r,out vec3 intersect){
    vec3 oc = orig - center;
    float b = dot(oc,dir);
    float c = dot(oc,oc) - r * r;
    if(c>0.0 && b > 0.0) return false;
    float discriminant = b*b -c;
    if(discriminant < 0.0) return false;
    float t= -b-sqrt(discriminant);
    if(t<0.0) return false;
    intersect = orig + t*dir;
    return true;  
}

//triangle intersection by miffy
bool hitTriangle(vec3 orig,vec3 dir,vec3 a,vec3 b,vec3 c,out vec3 uvt,out vec3 triangleNormal){
   float eps=1e-8;
   vec3 ab=b-a;
   vec3 ac=c-a;

   triangleNormal = normalize(cross(ab,ac));
   vec3 n=cross(dir,ac);

   float det=dot(ab,n);
   // if the determinant is negative the triangle is backfacing
   // if the determinant is close to 0, the ray misses the triangl
   if(det<=eps){ return false;}

   vec3 ao=orig-a;
   float u=dot(ao,n)/det;
   if(u<0.0 || u>1.0){ return false;}

   vec3 e=cross(ao,ab);
   float v=dot(dir,e)/det;
   if(v<0.0||u+v>1.0){ return false;}

   float t= dot(ac,e)/det;
   uvt = vec3(u,v,t);
   return true;
}


void Camera(out Ray ray, vec3 lookAt, vec3 up, float angle, float aspect) {

    vec3 g = normalize(lookAt - ray.orig);
    vec3 u = normalize(cross(g, up));
    vec3 v = normalize(cross(u, g));
    u = u * tan(radians(angle * .5));
    v = v * tan(radians(angle * .5)) / aspect;
    ray.dir = normalize(g + ray.dir.x * u + ray.dir.y * v);

}

//return intersection point with lightSource for the shadow ray
vec3 hitLightSource(Ray R_, Sphere sphere){
    vec3 hit = vec3(0.0,0.0,0.0);
    float mindist = -1000.;
    vec3 intersect;
    bool isHit = hitSphere(R_.orig,R_.dir,sphere.center,sphere.radius,hit);

    if(isHit && hit.z > mindist)
    {
        intersect = hit;

    }

    return intersect; 
}


//return intersection point with the mesh for the shadow ray
vec3 hitMesh(Ray R_){
    float mindist = -1000.;
    vec4 a = vec4(0.0), b = vec4(0.0), c = vec4(0.0);
    vec3 intersect = vec3(0.0,0.0,0.0);

    for (int i = 0; i < vertsCount; i += 3) {
        a = texelFetch(uMeshData, ivec2(i, 0), 0);
        b = texelFetchOffset(uMeshData, ivec2(i, 0), 0, ivec2(1, 0));
        c = texelFetchOffset(uMeshData, ivec2(i, 0), 0, ivec2(2, 0));

        vec3 triangleNormal;
        vec3 uvt;
        bool isHit = hitTriangle(R_.orig,R_.dir, a.xyz,b.xyz,c.xyz,uvt, triangleNormal);
        if (isHit) {
            intersect = R_.orig + R_.dir*uvt.z;
            float z = intersect.z;
            if (z>mindist) {
             mindist = z;
            }
        }      
    }
    return intersect;
}

//this is where if it is shadow we multiply the color with vec3(.4,.4,.4) else with vec3(1.,1.,1.,) so it does not affect the color if its not a shadow
vec3 calcShadow(Sphere lightSource, vec3 hitPos){
    vec3 color;

    vec3 lightDir =  normalize(lightSource.center-hitPos);
    Ray shadowRay = Ray(hitPos, lightDir);

    vec3 isHitLightDir = hitLightSource(shadowRay,lightSource);
    vec3 isHitMesh = hitMesh(shadowRay);

    if (isHitMesh.z > isHitLightDir.z ) {
        color = vec3(0.4,0.4,0.4);
    }else{
        color = vec3(1.,1.,1.);    
    }
    return color;
}

//function that it affects the mesh if it is hit by light we multiply with color of the Hitpoint with diffuse 
vec3 getLight(vec3 color, Sphere sphere, vec3 intersect, vec3 normal){
    vec3 lightDir =  normalize(sphere.center-intersect);
    float diffuse = clamp(dot(lightDir, normal), 0., 1.);
    return color*diffuse;
}


// we check if a ray intersected the scene, if it does we return the hitPos of the inteersection,
// the normal of that hitpoint the material and this bool isSphere if it intersectesd the floor, which is a giant sphere(in order to make it a floor)
bool hitScene(Ray R_, out vec3 hitPos, out vec3 normal, out Material material, Sphere sphere, out bool isShpere, Sphere lightSource){  // na thimithw na thesw to isShpere false stin trace synartisi

    vec4 a = vec4(0.0), b = vec4(0.0), c = vec4(0.0);
    float mindist = -1000.;
    bool weHitSomething = false;
    vec3 hitPos1 = vec3(0.);
    vec3 triangleNormal = vec3(0.,0.,0.);
    vec3 sphereNormal;


    //here we chck all the mesh if we hit a triangle if the mesh and we keep the closest hitpoint
    for (int i = 0; i < vertsCount; i += 3) {

        a = texelFetch(uMeshData, ivec2(i, 0), 0);
        b = texelFetchOffset(uMeshData, ivec2(i, 0), 0, ivec2(1, 0));
        c = texelFetchOffset(uMeshData, ivec2(i, 0), 0, ivec2(2, 0));

        vec3 uvt;
        bool isHit = hitTriangle(R_.orig,R_.dir, a.xyz,b.xyz,c.xyz,uvt, triangleNormal);
        if (isHit) {
            vec3 intersect = R_.orig + R_.dir*uvt.z;
            float z = intersect.z;
            if (z>mindist) {
                hitPos1 = intersect;

                mindist = z;
            }
        }      
    }


    //here we check if it intersected the floor which is a sphere and we keep the position of the hitPos
    vec3 hit = vec3(0.);
    bool isHit = hitSphere(R_.orig,R_.dir,sphere.center,sphere.radius,hit);

    if(isHit && hit.z > mindist)
    {
        mindist = hit.z;
        sphereNormal = (hit - sphere.center) / sphere.radius;
    }



    //here we have probably have 2 intersection points, one of a sphere, and one of a triangle
    // we keep the max of them cause the min dist is actually -1000. so we keep the closest hitpos

    float flag = max(hitPos1.z, hit.z);

    //based of the type of the interection(triangle or sphere) we assign to the mesh or the floor the material type, the normal and all the
    //information Trace function needs 
    //if we intersected something we set weHitSomething to true

    if ((flag == hitPos1.z) && (flag > -1000.)) {
        weHitSomething = true;
        material.type = METAL;
        material.albedo = vec3(0.9, 0.9, 0.9);
        normal = triangleNormal;
        hitPos = hitPos1;
        isShpere = false;
    }
    else if ((flag == hit.z) && (flag > -1000.)) {
        weHitSomething = true;
        material.type = LAMB;
        material.albedo = vec3(0., 0.9, 0.9);
        normal = sphereNormal;
        hitPos = hit;
        isShpere = true;
    }
    return weHitSomething;
}



//Trace is the main function of the max bounces
vec3 Trace(out Ray ray, Sphere floor, Sphere lightSource){

    vec3 hitPos, normal;
    bool isShpere;
    Material material;
    vec3 color = vec3(0.);
    vec3 attenuation = vec3(1.);
    vec3 light, shadow;

    //this if for every ray to bounce 4 times.(hopefully)
    for(int i=0; i< MAX_BOUNCES; i++){

        // we check if we hit something
        if(hitScene(ray, hitPos, normal, material, floor, isShpere, lightSource)){

            //we check the material type(if it is metal it is refering to the mesh)
            if (material.type == METAL) {

               //we calculate the new direction

                vec3 direction = reflect(ray.dir, normal);

                //here we check if the new direction and the hitPos normal is >0 then i do all the calculations 
                //and we start the new ray from the hitPos to the reflected direction

                // HERE is the problem for some reason it passes the dot product !!!!!!!
                //and it enters in the else where it assigns the color to hitPos  !!!!!!!

                if (dot(direction,normal) > 0.) {
                    ray = Ray(hitPos, direction); 
                    light = getLight(color, lightSource,hitPos, normal);
                    shadow = calcShadow(lightSource, hitPos);
                    color *= material.albedo * attenuation * light *shadow;
                    attenuation *= material.albedo;
                }

                else{

                    color = hitPos;
                }
            }

             if (material.type == LAMB) {
                vec3 direction = reflect(ray.dir, normal);
                if (dot(direction,normal) > 0.) {
                    ray = Ray(hitPos, direction);
                    light = getLight(color, lightSource,hitPos, normal);
                    shadow = calcShadow(lightSource, hitPos);
                    color *= material.albedo * attenuation*light*shadow;
                    attenuation *= material.albedo;
                }
                else{
                //   color = hitPos;
                }
            }
        }

        else{
            color = attenuation;
        }
    }

    return color;
}


void main() {

    //initialize lightSource, floor, Ray, camera
    Sphere lightSource = Sphere(vec3(1.,3.,1.), 0.18);
    Sphere floor  = Sphere(vec3(0., -1e3, 0.), 1e3);
    R_ = Ray(vec3(0.0, 1.0, 6.0), vec3(vuv, -1.));
    Camera(R_, vec3(0., 0., 1.), vec3(0., 1., 0.), 90.0, (Res.x / Res.y));

    // rotation
    R_.dir = mat3(uRot) * R_.dir;
    R_.orig = mat3(uRot) * R_.orig;

    //color coming from the trace function
    vec3 color = Trace(R_, floor, lightSource);

    fragColor.rgb = color;
    fragColor.a = 1.0;
}

Я хочу знать, сделал ли я что-то в корне неправильно hitScene и Trace .Треугольные пересечения и освещение работали нормально без рекурсии (когда у меня все они были в основной функции).

В моей функции hitScene я проверяю на 2 пересечения.Один с полом, который является гигантской сферой, а другой с остальной частью сетки, и я возвращаю нормаль позиции удара, позиции удара и материала удара.Затем я возвращаю его в функцию трассировки.

Там на основе материала я вычисляю новый отраженный луч и применяю материалы.Ясно, что что-то пошло не так, и я надеюсь, что получу подсказку, с чего начать.

this is what i get, where i iam supposed to get a scene with a floor 1 cube and 2 ico spheres

Я внес некоторые незначительные изменения, и я 'Я получаю этот результат.И, как вы видите, он не отображается правильно за сферами enter image description here

...