0.简介
前面的反射效果已经和非光追渲染有很大区别了,这回加上折射计算,效果会更好。
1.折射计算
折射计算相对反射要复杂一点,折射公式网上有的是,我就不在这里进行推导和详细讲解了,有需要的可以看下面这篇博客。
2.添加计算代码
在之前的反射光线附近添加折射光线计算代码,然后折射也进行光追迭代。
光线追踪迭代函数。
Ray rayTrac(Ray ray, vector<Polygon*> s, int times)
{
Ray r(vec3(0, 0, 0), vec3(0, 0, 0), 0, vec3(0, 0, 0), nullptr);
if (times <= 0)
return r;
float minDistance = FLT_MAX;
for (auto obj : s)
{
//找到最近的物体
Ray rayTemp = obj->intersect(ray);
if (rayTemp.polygon && rayTemp.distance < minDistance)
{
minDistance = rayTemp.distance;
r = rayTemp;
}
}
if (r.polygon == nullptr)
return Ray(vec3(0, 0, 0), vec3(0, 0, 0), 0, vec3(0, 0, 0), nullptr);
//计算反射光线
vec3 reflectRayNormal = r.normal;
/*if (dot(r.direction , reflectRayNormal) > 0)
reflectRayNormal = -reflectRayNormal;*/
//构造折射光线
float itea = ((Polygon*)(r.polygon))->m->refract;
float cosa1 = abs(dot(r.direction ,reflectRayNormal));
float cosa2 = sqrt(1 - (1 / (itea * itea) * (1 - cosa1 * cosa1)));
Ray refractRay = Ray(normalize((1 / itea) * r.direction + (cosa1 / itea - cosa2) * reflectRayNormal), r.end.position, 0, vec3(0, 0, 0), nullptr);
//构造反射光线
Ray reflectRay = Ray(normalize(r.direction - (2 * dot(r.direction, reflectRayNormal)) * reflectRayNormal), r.end.position, 0, vec3(0, 0, 0), nullptr);
//获得反射光线方向
refractRay = rayTrac(refractRay, s, times - 1);
reflectRay = rayTrac(reflectRay, s, times - 1);
//计算物体返回的颜色
r = ((Polygon*)(r.polygon))->sample(r, reflectRay, refractRay);
return r;
}
对于平面有折射的处理代码,球也有,但是之前出了点问题,所以调试了好几次才找到,这里需要注意的是,如果光线进入球体内,那么折射光线会穿过球体,所以要区分光线在球体内发射还是在球外,对于平面,要考虑平面部分正反面,两面都能反光和折射。
Ray Sphere::intersect(Ray ray)
{
Ray result(ray.direction,ray.position,ray.intensity, vec3(0,0,0), nullptr);
//计算球和光线的向量
vec3 v = ray.position - center;
//如果光源在球体表面或者内部,要专门注意这种情况
if (abs(length(v) - radius) < 0.001 && dot(normalize(v) , ray.direction) <= 0)
{
result.polygon = this;
float cosa = glm::dot(normalize((center - ray.position)), normalize(ray.direction));//normalize(abs((center - ray.position))*normalize(ray.direction));
result.distance = 2 * radius * abs(cosa);
result.end = ray.getEndPoint(result.distance);
result.normal = -normalize(result.end.position - center);
return result;
}
float disSubR = dot(v , v) - (radius * radius);
float ray_v_dot = dot(ray.direction , v);
if (ray_v_dot <= 0)
{
float discr = ray_v_dot * ray_v_dot - disSubR;
if (discr >= 0)
{
result.polygon = this;
result.distance = -ray_v_dot - sqrt(discr);
result.end = ray.getEndPoint(result.distance);
result.normal = normalize(result.end.position - center);
return result;
}
}
return result;
}