C++ 光线跟踪阴影
因此,我在网上读到了光线追踪的相关内容,并开始在业余时间从头开始编写光线跟踪器。我用C++,我已经学了大约一个月了。我读过网上光线追踪的理论,到目前为止,它工作得很好。它只是一个基本的光线跟踪器,既不使用模型也不使用纹理 起初它做了一个光线投射器,对结果非常满意。 然后我尝试了多个对象,它也起了作用。我只是在这个实现中使用了漫反射着色,并在未着色的点将灯光的颜色添加到对象颜色中。 不幸的是,该代码不适用于多个光源。然后我开始重写我的代码,这样它就可以支持多个灯光。 我还阅读了Phong illumination并开始工作: 它甚至适用于多个灯光: 到目前为止,我很高兴,但现在我有点卡住了。我已经试着解决这个问题很长一段时间了,但我什么也没想到。当我添加第二个球体甚至第三个球体时,只有最后一个球体被照亮。最后我指的是数组中存储所有对象的对象。请参见下面的代码。 显然,紫色球体应该具有类似的照明,因为它们的中心位于同一平面上。令我惊讶的是,球体只有“环境照明-->着色”,而实际情况并非如此 现在我的跟踪函数:C++ 光线跟踪阴影,c++,shadow,raytracing,phong,C++,Shadow,Raytracing,Phong,因此,我在网上读到了光线追踪的相关内容,并开始在业余时间从头开始编写光线跟踪器。我用C++,我已经学了大约一个月了。我读过网上光线追踪的理论,到目前为止,它工作得很好。它只是一个基本的光线跟踪器,既不使用模型也不使用纹理 起初它做了一个光线投射器,对结果非常满意。 然后我尝试了多个对象,它也起了作用。我只是在这个实现中使用了漫反射着色,并在未着色的点将灯光的颜色添加到对象颜色中。 不幸的是,该代码不适用于多个光源。然后我开始重写我的代码,这样它就可以支持多个灯光。 我还阅读了Phong ill
Colour raytrace(const Ray &r, const int &depth)
{
//first find the nearest intersection of a ray with an object
//go through all objects an find the one with the lowest parameter
double t, t_min = INFINITY;
int index_nearObj = -1;//-1 to know if obj found
for(int i = 0; i < objSize; i++)
{
//skip light src
if(!dynamic_cast<Light *>(objects[i]))
{
t = objects[i]->findParam(r);
if(t > 0 && t < t_min) //if there is an intersection and
//its distance is lower than the current min --> new min
{
t_min = t;
index_nearObj = i;
}
}
}
//now that we have the nearest intersection, calc the intersection point
//and the normal at that point
//r.position + t * r.direction
if(t_min < 0 || t_min == INFINITY) //no intersection --> return background Colour
return White;
Vector intersect = r.getOrigin() + r.getDirection()*t;
Vector normal = objects[index_nearObj]->NormalAtIntersect(intersect);
//then calculate light ,shading and colour
Ray shadowRay;
Ray rRefl;//reflected ray
bool shadowed;
double t_light = -1;
Colour finalColour = White;
Colour objectColor = objects[index_nearObj]->getColour();
Colour localColour;
Vector tmpv;
//get material properties
double ka = 0.1; //ambient coefficient
double kd; //diffuse coefficient
double ks; //specular coefficient
Colour ambient = ka * objectColor; //ambient component
//the minimum Colour the obj has, even if object is not hit by light
Colour diffuse, specular;
double brightness;
int index = -1;
localColour = ambient;
//look if the object is in shadow or light
//do this by casting a ray from the obj and
// check if there is an intersection with another obj
for(int i = 0; i < objSize; i++)
{
if(dynamic_cast<Light *>(objects[i])) //if object is a light
{//for each light
shadowed = false;
//create Ray to light
//its origin is the intersection point
//its direction is the position of the light - intersection
tmpv = objects[i]->getPosition() - intersect;
shadowRay = Ray(intersect + (!tmpv) * BIAS, tmpv);
//the ray construcor automatically normalizes its direction
t_light = objects[i]->findParam(shadowRay);
if(t_light < 0) //no imtersect, which is quite impossible
continue;
//then we check if that Ray intersects one object that is not a light
for(int j = 0; j < objSize; j++)
{
if(!dynamic_cast<Light *>(objects[j]))//if obj is not a light
{
//we compute the distance to the object and compare it
//to the light distance, for each light seperately
//if it is smaller we know the light is behind the object
//--> shadowed by this light
t = objects[j]->findParam(shadowRay);
if(t < 0) // no intersection
continue;
if(t < t_light) // intersection that creates shadow
shadowed = true;
else
{
shadowed = false;
index = j;//not using the index now,maybe later
break;
}
}
}
//we know if intersection is shadowed or not
if(!shadowed)// if obj is not shadowed
{
rRefl = objects[index_nearObj]->calcReflectingRay(shadowRay, intersect); //reflected ray from ligh src, for ks
kd = maximum(0.0, (normal|shadowRay.getDirection()));
ks = pow(maximum(0.0, (r.getDirection()|rRefl.getDirection())), objects[index_nearObj]->getMaterial().shininess);
diffuse = kd * objectColor;// * objects[i]->getColour();
specular = ks * objects[i]->getColour();//not sure if obj needs specular colour
brightness = 1 /(1 + t_light * DISTANCE_DEPENDENCY_LIGHT);
localColour += brightness * (diffuse + specular);
}
}
}
//handle reflection
//handle transmission
//combine colours
//localcolour+reflectedcolour*refl_coeff + transmittedcolor*transmission coeff
finalColour = localColour; //+reflcol+ transmcol
return finalColour;
}
for(uint32_t y = 0; y < h; y++)
{
for(uint32_t x = 0; x < w; x++)
{
//pixel coordinates for the scene, depends on implementation...here camera on z axis
pixel.X() = ((x+0.5)/w-0.5)*aspectRatio *angle;
pixel.Y() = (0.5 - (y+0.5)/w)*angle;
pixel.Z() = look_at.getZ();//-1, cam at 0,0,0
rTmp = Ray(cam.getOrigin(), pixel - cam.getOrigin());
cTmp = raytrace(rTmp, depth);//depth == 0
pic.setPixel(y, x, cTmp);//writes colour of pixel in picture
}
}
我使用对象指针的全局数组来存储世界的所有灯光、球体等:
Object *objects[objSize];
我知道我的代码乱七八糟,但如果有人知道发生了什么,我将非常感激
编辑1我添加了图片
编辑2更新的代码,修复了一个小错误。仍然没有解决办法
更新:添加了渲染代码,可创建光线。发现问题
我设法使用Linux和gcc调试了您的光线跟踪器。关于这个问题,嗯。。。一旦我找到了它,我就有一种强烈的冲动,想用头反复敲击键盘 你的算法是正确的,只是有一点小细节:
Vector intersect = r.getOrigin() + r.getDirection()*t;
计算交点时,使用t
而不是t\u min
修复方法包括将上述行更改为:
Vector intersect = r.getOrigin() + r.getDirection()*t_min;
正确的输出如下所示:
//then we check if that Ray intersects one object that is not a light
for (int j = 0; j < objSize; j++)
{
// Exclude lights AND the closest object found
if(j != index_nearObj && !dynamic_cast<Light *>(objects[j]))
{
//we compute the distance to the object and compare it
//to the light distance, for each light seperately
//if it is smaller we know the light is behind the object
//--> shadowed by this light
t = objects[j]->findParam(shadowRay);
// If the intersection point lies between the object and the light source,
// then the object is in shadow!
if (t >= 0 && t < t_light)
{
// Set the flag and stop the cycle
shadowed = true;
break;
}
}
}
其他建议
我认为问题在于阴影光线循环:
//then we check if that Ray intersects one object that is not a light
for(int j = 0; j < objSize; j++)
{
if(!dynamic_cast<Light *>(objects[j]))//if obj is not a light
{
//we compute the distance to the object and compare it
//to the light distance, for each light seperately
//if it is smaller we know the light is behind the object
//--> shadowed by this light
t = objects[j]->findParam(shadowRay);
if(t < 0) // no intersection
continue;
if(t < t_light) // intersection that creates shadow
shadowed = true;
else
{
shadowed = false;
index = j;//not using the index now,maybe later
break;
}
}
}
其他一些建议:
- 通过添加一个函数来重构渲染代码,该函数给定一条光线,可以找到与场景最近/第一个交点。这避免了代码重复
- 不要为点积和规范化重载运算符:使用专用函数
- 尽量减少变量的范围:这样可以提高代码的可读性
- 继续探索光线追踪的东西,因为它太棒了:D
操作符
不是最好的主意,因为它的优先级错误,而且非常非常规。什么是运算符代码>在<代码>相交+!(objects[i]->getPosition()-intersect)*BIAS
?我知道,运算符|不是点积的最佳方法,因为它的优先级非常低,但我认为我在每个点积周围使用了大括号。我选择使用它,因为我也在纸上使用它。至于这个!运算符,我用它来规范化向量。因为它的优先级高于乘法,所以不应该有问题。我猜intersect函数有问题,但我不确定。不管怎样,谢谢你的意见。@TavianBarnes:我查看了你的网站,尤其是Dimension,我不得不说它看起来棒极了!!我喜欢这种方法,肯定比我的好,但它仍然不能解决多目标问题……也许我的求交函数是错的?我不知道…但是谢谢你的帮助,我真的很感激。如果你感兴趣,我可以给你发送源代码。上传你的项目并链接到这里,我会尝试一下。Matrix.h头丢失了!(编辑:然而,它似乎没有被使用:P)是的,我添加它只是为了防止我想要旋转或平移矩阵,我不使用atm。你使用哪种编译器?你能把你从电脑上得到的输出贴出来吗?我的是这个,看起来很不对:
//then we check if that Ray intersects one object that is not a light
for(int j = 0; j < objSize; j++)
{
if(!dynamic_cast<Light *>(objects[j]))//if obj is not a light
{
//we compute the distance to the object and compare it
//to the light distance, for each light seperately
//if it is smaller we know the light is behind the object
//--> shadowed by this light
t = objects[j]->findParam(shadowRay);
if(t < 0) // no intersection
continue;
if(t < t_light) // intersection that creates shadow
shadowed = true;
else
{
shadowed = false;
index = j;//not using the index now,maybe later
break;
}
}
}
//then we check if that Ray intersects one object that is not a light
for (int j = 0; j < objSize; j++)
{
// Exclude lights AND the closest object found
if(j != index_nearObj && !dynamic_cast<Light *>(objects[j]))
{
//we compute the distance to the object and compare it
//to the light distance, for each light seperately
//if it is smaller we know the light is behind the object
//--> shadowed by this light
t = objects[j]->findParam(shadowRay);
// If the intersection point lies between the object and the light source,
// then the object is in shadow!
if (t >= 0 && t < t_light)
{
// Set the flag and stop the cycle
shadowed = true;
break;
}
}
}