【发布时间】:2017-07-02 07:16:38
【问题描述】:
我目前正在开发一个光线追踪器,只是为了好玩,但我在折射处理方面遇到了麻烦。
整个光线追踪器的代码源可以找到on Github编辑:代码迁移to Gitlab。
这是渲染的图像:
右侧球体的折射率设置为 1.5(玻璃)。
在折射之上,我想处理一个定义为这样的“透明度”系数:
- 0 --> 对象 100% 不透明
- 1 --> 对象 100% 透明(没有原始对象颜色的痕迹)
这个球体的透明度为 1。
这是处理折射部分的代码。可以找到on github here。
Color handleTransparency(const Scene& scene,
const Ray& ray,
const IntersectionData& data,
uint8 depth)
{
Ray refracted(RayType::Transparency, data.point, ray.getDirection());
Float_t eta = data.material->getRefraction();
if (eta != 1 && eta > Globals::Epsilon)
refracted.setDirection(Tools::Refract(ray.getDirection(), data.normal, eta));
refracted.setOrigin(data.point + Globals::Epsilon * refracted.getDirection());
return inter(scene, refracted, depth + 1);
}
// http://graphics.stanford.edu/courses/cs148-10-summer/docs/2006--degreve--reflection_refraction.pdf
Float_t getFresnelReflectance(const IntersectionData& data, const Ray& ray)
{
Float_t n = data.material->getRefraction();
Float_t cosI = -Tools::DotProduct(ray.getDirection(), data.normal);
Float_t sin2T = n * n * (Float_t(1.0) - cosI * cosI);
if (sin2T > 1.0)
return 1.0;
using std::sqrt;
Float_t cosT = sqrt(1.0 - sin2T);
Float_t rPer = (n * cosI - cosT) / (n * cosI + cosT);
Float_t rPar = (cosI - n * cosT) / (cosI + n * cosT);
return (rPer * rPer + rPar * rPar) / Float_t(2.0);
}
Color handleReflectionAndRefraction(const Scene& scene,
const Ray& ray,
const IntersectionData& data,
uint8 depth)
{
bool hasReflexion = data.material->getReflexion() > Globals::Epsilon;
bool hasTransparency = data.material->getTransparency() > Globals::Epsilon;
if (!(hasReflexion || hasTransparency) || depth >= MAX_DEPTH)
return 0;
Float_t reflectance = data.material->getReflexion();
Float_t transmittance = data.material->getTransparency();
Color reflexion;
Color transparency;
if (hasReflexion && hasTransparency)
{
reflectance = getFresnelReflectance(data, ray);
transmittance = 1.0 - reflectance;
}
if (hasReflexion)
reflexion = handleReflection(scene, ray, data, depth) * reflectance;
if (hasTransparency)
transparency = handleTransparency(scene, ray, data, depth) * transmittance;
return reflexion + transparency;
}
Tools::Refract 只是在内部调用glm::refract。 (这样我可以根据需要轻松更改)
我不处理 n1 和 n2 的概念:n2 被认为始终是空气 1。
我错过了什么明显的东西吗?
编辑
在添加了一种方法来了解光线是否在对象内部(如果是,则否定法线)我有这个:
在四处寻找帮助时,我偶然发现了this 的帖子,但我认为答案无法回答任何问题。通过阅读它,我根本不明白我应该做什么。
编辑 2
我已经尝试了很多东西,我目前处于这一点:
这更好,但我仍然不确定它是否正确。我用这张图片作为灵感:
但是这个使用了两个折射率(为了更接近现实),而我想简化并始终将空气视为第二种(进出)材料。
我在我的代码中进行了本质上的更改:
inline Vec_t Refract(Vec_t v, const IntersectionData& data, Float_t eta)
{
Float_t n = eta;
if (data.isInside)
n = 1.0 / n;
double cosI = Tools::DotProduct(v, data.normal);
return v * n - data.normal * (-cosI + n * cosI);
}
这是相同领域的另一个视图:
【问题讨论】:
-
if (eta != 1这会促进 eta 加倍还是促进 1 浮动? -
我认为这会促进 1 浮动。 (顺便说一句,
Float_t是double) -
你确定
eta > Globals::Epsilon是真的吗?也许有些光线无法进入球体并且无法到达相机?您是否尝试过从正交角度看光源?你是在做反向追踪光线追踪吗? -
是的,
data.material->getRefraction()返回一个常量。这是一个用户定义的值,给出给定对象的折射指数。 (在这个特定的测试用例中它的值为1.5) -
transmittance = 1.0 - reflectance;覆盖Float_t transmittance = data.material->getTransparency();也许?
标签: c++ raytracing