Плавные тени от теневых лучей в GLSL работают некорректно - PullRequest
0 голосов
/ 04 марта 2019

Я реализую трассировщик лучей с точками сетки в WebGL.Несколько слов для моей реализации.

Я передаю значения вершин и нормали вершин в текстурах и распаковываю их во фрагментном шейдере, где выполняется алгоритм трассировки лучей.Сферы, состоящие из треугольников, имели плоский затененный вид, затем я умножил нормали вершин треугольника на барицентрические координаты, и у меня был гладкий вид в сферах треугольника.Проблема в том, что, когда я вычисляю тень, она выглядит так же «остро».Я предоставлю распечатку с результатами и код того, как я в настоящее время вычисляю теневые лучи.

enter image description here

Как видите, поверхность сферы выглядит гладкой, нотень - это не

вот функция calcShadow, которую я использую:

vec3 calcShadow(Sphere lightSource, vec3 hitPos){
    vec3 color;

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

    float isHitLight = hitLightSource(shadowRay,lightSource);
    float isHitMesh = hitMesh(shadowRay);

    if (isHitMesh < isHitLight) {
        color = vec3(0.5,0.5,0.5);
    }else{
        color = vec3(1.,1.,1.);    
    }
    return color;
}

hitMesh:

float 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;
        float z;

        bool isHit = hitTriangleSecond(R_.orig, R_.dir, a.xyz, b.xyz, c.xyz, uvt, triangleNormal, intersect, z);;
        if (isHit) {
            if (z<mindist && z > 0.001)  mindist = z;
        } 

    }
    return mindist;
}

, и это второй метод hitTriangke для треугольникатест пересечения:

bool hitTriangleSecond( vec3 orig, vec3 dir, vec3 a, vec3 b, vec3 c,
                        out vec3 uvt, out vec3 N, out vec3 x, out float dist) {

    float eps=1e-8;

    vec3 ab = b - a;
    vec3 ac = c - a;

    N = normalize(cross(ab, ac));

    dist = dot(a - orig, N) / dot(dir, N);
    x    = orig + dir * dist;

    vec3 ax = x - a;

    float d00 = dot(ab, ab);
    float d01 = dot(ab, ac);
    float d11 = dot(ac, ac);
    float d20 = dot(ax, ab);
    float d21 = dot(ax, ac);

    float denom = d00 * d11 - d01 * d01; // determinant

    // if the determinant is negative the triangle is backfacing
    // if the determinant is close to 0, the ray misses the triangl
    if ( denom <= eps )
        return false;

    uvt.y = (d11 * d20 - d01 * d21) / denom;
    if ( uvt.y < 0.0 || uvt.y > 1.0 )
        return false;

    uvt.z = (d00 * d21 - d01 * d20) / denom;
    if ( uvt.z < 0.0 || uvt.z > 1.0 )
        return false;

    uvt.x = 1.0 - uvt.y - uvt.z;
    if ( uvt.x < 0.0 || uvt.x > 1.0 )
        return false;

    return true;
}

Я знаю, что нет вычисления интерполированной нормали треугольника, но у меня вопрос: нужно ли обновлять функцию hitTriangle, чтобы она возвращала интерполированную нормаль на основе нормалей вершины?или мне нужно рассчитать барицентрические координаты и затем вставить его в функцию треугольника попадания?Я вроде не понимаю, как реализовать гладкие тени ...

ниже - мой цикл для цикла, где я распаковываю сетку и вычисляю интерполированную нормаль попадания, и вот как я получил гладкую поверхность:

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));

            aN = texelFetch(uNormData, ivec2(i, 0), 0);
            bN = texelFetchOffset(uNormData, ivec2(i, 0), 0, ivec2(1, 0));
            cN = texelFetchOffset(uNormData, ivec2(i, 0), 0, ivec2(2, 0));

            vec3 uvt;
            vec3 intersect;
            float z;
            bool isHit = hitTriangleSecond(R_.orig, R_.dir, a.xyz, b.xyz, c.xyz, uvt, triangleNormal, intersect, z);
            if (isHit) {

                if (z<mindist && z > 0.001) {
                    hitPos1 = intersect;

                    mindist = z;
                    weHitSomething = true;
                    material.type = DIEL;
                    material.albedo = vec3(.8, .3, .4);
                    normal = aN.xyz*uvt.x + bN.xyz*uvt.y + cN.xyz*uvt.z;

                    hitPos = hitPos1;            
                }
            }      
        } 

1 Ответ

0 голосов
/ 05 марта 2019

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

Лучлитье зависит от пересечения треугольников, поэтому для гладких теней вам нужна плавная геометрия в заклинателе теней - то есть больше треугольников.Такие методы, как нормальное картирование, работают для освещения, потому что вы можете подделать приблизительную интенсивность света на основе измененной ориентации, но на самом деле нет никакого смещения поверхности, которое меняет физическую геометрию, так что это не поможет исправить любое неправильное тестирование удара.

Что вам действительно нужно для теней, так это больше геометрии, чтобы вы точно описали форму края силуэта отбрасывания теней, используя настоящие треугольники.

...