Преломление в ray tracer дает нечетные результаты, как мне объединить все цветовые компоненты?

#c #renderin& #raytracin& #phon& #fresnel

#c #рендеринг #трассировка лучей #фонг #френель

Вопрос:

Я пишу трассировщик лучей, пока только со сферами, на C , и после реализации модели отражения Фонга, теней и отражений, все, казалось, работало нормально. Когда я реализовал преломления и fresnel, я, похоже, не могу заставить вещи выглядеть правильно. Я думал, может ли это быть из-за того, как я перемещаю источник луча, когда нахожусь внутри / снаружи объекта sphere, но после попыток и поиска в Goo&le я все еще не могу понять это правильно.

Ниже приведено изображение. Серый фон представляет собой большую рассеянную сферу, а меньшая синяя сфера за красной сферой также рассеянная. Остальные являются отражающими и преломляющими с ior 1.5-1.6. Есть два точечных источника света, немного слева и один немного справа.

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

 Vec3 trace(Vec3amp; rayOri&in, Vec3amp; rayDirection, unsi&ned recursiveDepth, std::vector<Sphere&&t;amp; spheres, std::vector<Li&ht&&t;amp; li&hts, RenderOptionamp; options) {
    //Findin& nearest intersectin& object
    float nearestDepth = 1e8;
    Sphere nearestObject;
    unsi&ned id = 0;
    Vec3 ori&in = rayOri&in   rayDirection * BIAS;
    for (unsi&ned i = 0; i < spheres.size();   i) {
        if (spheres[i].intersect(ori&in, rayDirection)) {
            if (spheres[i].depth < nearestDepth) {
                nearestDepth = spheres[i].depth;
                nearestObject = spheres[i];
                id = i;
            }
        }
    }

    Vec3 back&roundColor = Vec3(0.0f, 0.0f, 0.0f);
    if (!nearestObject.exists) {
        //No intersectin& object -&&t; back&round cooler
        return back&roundColor;
    } else {    
        Vec3 totalColor;
        Vec3 li&htDirection;

        //Ambient color
        totalColor  = options.ambientColor * nearestObject.ambientColor; //Ambient color set to 0

        //Calculate fresnel, update fresnelReflection amp; fresnelRefraction of nearestObject sent in
        fresnel(rayDirection, nearestObject);

        //Recursive reflection and refraction
        if ((nearestObject.reflectivity &&t; 0.0f || nearestObject.transparency &&t; 0.0f) amp;amp; recursiveDepth < options.recursionDepth) {
            //Reflection case
            if (nearestObject.fresnelReflection &&t; 0.0f) {
                Vec3 reflection = computeReflection(rayDirection, nearestObject.normal);
                Vec3 reflectedColor = trace(nearestObject.intersection, reflection,   recursiveDepth, spheres, li&hts, options);
                totalColor  = reflectedColor * nearestObject.fresnelReflection;
            }
            //Refraction case
            if (nearestObject.fresnelRefraction &&t; 0.0f) {
                Vec3 refractionDirection = computeRefraction(rayDirection, nearestObject.normal, nearestObject.indexOfRefraction, nearestObject.intersection);
                Vec3 refractedColor = trace(nearestObject.intersection, refractionDirection,   recursiveDepth, spheres, li&hts, options);
                totalColor  = refractedColor * nearestObject.fresnelRefraction;
            }
        }
    
        //Phon& reflection model and shadows
        for (unsi&ned i = 0; i < li&hts.size();   i) {
            //Shadow ray
            Vec3 intersectionPointBias = nearestObject.intersection   nearestObject.normal * BIAS;
            Vec3 shadowRayDirection = li&hts[i].position - intersectionPointBias; //normalized in intersect function

            for (unsi&ned k = 0; k < spheres.size();   k) //kolla inte nearestObject mot si& själv
            {
                if (!spheres[k].intersect(intersectionPointBias, shadowRayDirection))
                {
                    //Diffuse
                    li&htDirection = li&hts[i].position - nearestObject.normal;
                    li&htDirection.normalize();
                    totalColor  = li&hts[i].diffuse * std::max(0.0f, nearestObject.normal.dot(li&htDirection)) * nearestObject.diffuseColor;

                    //Specular
                    Vec3 viewDirection = nearestObject.intersection - options.cameraOri&in;
                    viewDirection.normalize();
                    Vec3 reflection = li&htDirection - nearestObject.normal * 2 * (nearestObject.normal.dot(li&htDirection));
                    reflection.normalize();
                    totalColor  = li&hts[i].specular * nearestObject.specularColor * std::max(0.0f, pow(reflection.dot(viewDirection), nearestObject.shininessCoefficient));
                }
            }
        }
        return totalColor;
    }
}
  

Вот другие соответствующие функции:
Компьютерная преломление:

 Vec3 computeRefraction(const Vec3amp; I, const Vec3amp; N, const float amp;ior, Vec3amp; intersection) {
    Vec3 normal = N; normal.normalize();
    normal = normal;
    Vec3 incident = I; incident.normalize();
    float cosi = incident.dot(normal);
    float n1, n2;
    if (cosi &&t; 0.0f) { 
        //Incident and normal have same direction, INSIDE sphere
        n1 = ior;
        n2 = 1.0f;
        normal = -normal;
    } else { 
        //Incident and normal have opposite direction, OUTSIDE sphere
        n1 = 1.0f;
        n2 = ior;
        cosi = -cosi;
    }

    float eta = n1 / n2;
    float k = 1.0f - (eta * eta) * (1.0f - cosi * cosi);

    if (k < 0.0f) {   
        //internal reflection
        Vec3 reflectionRay = computeReflection(incident, normal);
        intersection = intersection   (normal * BIAS);
        return reflectionRay;
    } else {
        Vec3 refractionVector = incident * eta   normal * (eta * cosi - sqrt(k));
        refractionVector.normalize();
        intersection = intersection - (normal * BIAS);
        return refractionVector;
    }
}
  

френель:

 void fresnel(const Vec3amp; I, Sphereamp; obj) {
    Vec3 normal = obj.normal;
    Vec3 incident = I;
    float cosi = clamp(-1.0f, 1.0f, incident.dot(normal));
    float etai = 1.0f, etat = obj.indexOfRefraction;
    if (cosi &&t; 0) {
        std::swap(etai, etat);
    }
    float sint = etai / etat * sqrt(std::max(0.0f, 1 - cosi * cosi));
    if (sint &&t;= 1) {
        obj.fresnelReflection = 1.0f;
        obj.fresnelRefraction = 0.0f;
    } else {
        float cost = sqrt(std::max(0.0f, 1 - sint * sint));
        cosi = abs(cost);
        float Rs = ((etat * cosi) - (etai * cost)) / ((etat * cosi)   (etai * cost));
        float Rp = ((etai * cosi) - (etat * cost)) / ((etai * cosi)   (etat * cost));
        obj.fresnelReflection = (Rs * Rs   Rp * Rp) / 2;
        obj.fresnelRefraction = 1.0f - obj.fresnelReflection;
    }
}
  

отражение:

 Vec3 computeReflection(const Vec3amp; rayDirection, const Vec3amp; objectNormal){
    Vec3 normal = objectNormal;
    Vec3 incident = rayDirection;
    Vec3 reflection = incident - normal * (normal.dot(rayDirection)) * 2;
    reflection.normalize();
    return reflection;
}
  

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

Комментарии:

1. Это многовато кода, но при беглом просмотре я бы посоветовал вам упростить сцену: одна рассеянная сфера и одна прозрачная сфера (без других функций), т. Е. тестировать по одному объекту за раз. Далее вы можете протестировать свою функцию преломления изолированно. Составьте входные данные на листе бумаги, вычислите / сконструируйте результат, затем протестируйте свою функцию с этим и проверьте выходные данные. Наконец, ваша функция Френеля изменяет объекты в вашей сцене, в чем не должно быть необходимости. Поэтому вам следует присмотреться повнимательнее, если то, что вы там делаете, действительно необходимо.

2. Я вижу одну очень знакомую проблему. Везде, где вы вызываете trace функцию с точкой пересечения, вам нужно добавить смещение (очень небольшое число в направлении нормали). В противном случае луч снова попадет на тот же объект