#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∈
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
функцию с точкой пересечения, вам нужно добавить смещение (очень небольшое число в направлении нормали). В противном случае луч снова попадет на тот же объект