【问题标题】:Java: Ray Tracing: Glossy reflection coloringJava:光线追踪:光泽反射着色
【发布时间】:2016-10-01 07:01:28
【问题描述】:

我编写了一个光线追踪程序,它(目前)有两个表面光照选项:环境光照和反射光照。环境照明复制了自然表面如何散射光。反射显然复制了镜子如何反射光。一切正常,但我不知道如何将颜色与光泽反射混合。

反射算法返回颜色并递归工作。光线以参数化线的形式“投射”。当它们碰到反射表面时,它们会完美地反弹(以及我的这项工作的方法)。然后将这些反射光线作为参数再次调用反射算法。这种情况一直持续到当前光线照射到环境(非反射)表面或当前光线根本不照射到表面为止。

我现在计算颜色的方式是从后到前平均反射表面和新撞击表面的颜色。因此,光线早期击中的表面上的颜色比后来的表面颜色表示得更多。

如果颜色 A 是它撞击的第一个(反射)表面的颜色,颜色 B 是它撞击的第二个表面的颜色,C 是第三个表面的颜色,依此类推。所以最终返回的颜色将是 50% A、25% B、12.5% C...

我为此使用的方法实际上支持加权平均,因此镜像表面对最终颜色的影响较小。这里是:

public void addColor(Color b, double dimFac) {
    double red = c.getRed() * (1 - dimFac) + b.getRed() * dimFac;
    double green = c.getGreen() * (1 - dimFac) + b.getGreen() * dimFac;
    double blue = c.getBlue() * (1 - dimFac) + b.getBlue() * dimFac;
    c = new Color((int) red,
                  (int) green,
                  (int) blue);
}

这是该程序的屏幕截图。三个环境球体悬停在一个有光泽的反射平面上,“dimFac”为 0.5:

下面是同样的模拟,dimFac 为 1,因此镜子对最终颜色没有影响:

这里的 dimFac 是 0.8

这里是 0.1

也许只有我一个人,但这些反射看起来都不是非常逼真。我用作指导的是康奈尔大学的一个简报,除其他外,它确实提到了有关添加颜色的任何内容。镜子在一定程度上确实有颜色,我不知道混合颜色的正确方法。我做错了什么?

所以我从光线中获取颜色的方式如下。光线追踪器的每次迭代都从形状的初始化开始。该程序支持三种形状:平面、球体和矩形棱柱(最终只有 6 个平面)。我为每个形状都有一个类,以及一个可以存储每种形状类型(但每个对象只有一个)的类(称为 Shapes)。

形状制作完成后,一个类(称为 Projector)通过另一个称为 MasterLight 的类(它实际上包含基本光线追踪、阴影、反射和(现在)折射的方法)投射光线。

为了获得交叉点的颜色,我调用 getColor() 方法,该方法获取交叉点的向量(我如何存储 3d 点)。我用它来确定表面的无阴影颜色。如果表面没有纹理并且只是一种空白颜色(如上面的形状),则返回一个无阴影的颜色(这只是存储在每个形状类“Color c = Color.RED”中)。一个例子是 Color.RED

我采用该颜色并递归地将其插入 MasterLight 作为基础颜色,以获得阴影,就好像表面是正常的和环境的一样。此过程返回形状通常具有的阴影。现在 RGB 值可能是 (128, 0, 0);

public Color getColor(Vector v) {
    if (texturing) {
         return texturingAlgorithm;
    }
    else {
         return c;
    }
}

DimFac 的使用方式有可能是从 0 到 1 的任何值;现在在我的程序中,它是 0.8(这是通用着色常数。在环境着色中,我取我调暗颜色的值并将其乘以 0.8 并加上 0.2(1 - 0.8),这样最暗的颜色可以是其原始亮度的 0.2)。

addColor 在另一个名为 Intersection 的类中(我目前有 17 个,其中一个是枚举)。这存储了关于光线与形状相交的所有重要信息(颜色、位置、撞击表面的法线向量,以及与对象材质相关的一些其他常数)。颜色 c 是计算中该点的当前颜色。

每次反射迭代都会使用最新的表面颜色调用 addColor。更详细地说,如果(在上图中)一条光线刚刚从平面反弹并撞击一个球体并反弹到空旷的空间中,我首先在反弹点找到球体表面的颜色,这就是'c ' 被设定为。然后我用相交点的平面颜色(第一次)调用 addColor。

一旦我回溯了所有的反射,我就会留下一种颜色,这是我用来为特定光线的像素着色的颜色。

告诉我是否遗漏了什么或不清楚。

【问题讨论】:

  • 您能否提供一份您用来获取光线颜色的方法的副本?此外,您能否围绕您的 addColor() 方法提供一些上下文:dimFac 是每个对象的属性,就像在材质中一样?或者它是一个全球价值?你能解释一下你是如何使用Colorc的吗?

标签: java colors raytracing lighting


【解决方案1】:

您应该使用 Phong-Bui Tong 在 1975 年创建的 Phong 着色方法。Phong 方程将光照简化为三个部分:环境光、漫反射和镜面反射。

环境光是您的对象在完全黑暗中的照明。环境照明不受光源影响。

漫射光是基于交叉点的表面法线与来自交叉点的光矢量之间的角度的光亮度。

我相信您正在寻找镜面光。它基于从相交角到相机位置的矢量与光矢量关于表面的反射矢量之间的夹角。

以下是我通常使用 Phong 着色的方式:

  • 对于场景中的任何对象,定义三个常量:Ka(环境光)、Kd(漫射光)和 Ks(镜面光)。我们还将为您的对象的光泽度定义一个常数“n”。我会将这个值保持在 3 以上。
  • 求法向量和光向量的点积,我们暂时称这个量为“dF”。
  • 现在让我们计算反射向量:它是法线向量,乘以法线向量和光向量的点积,再乘以 2。减去光向量,如果法线向量和光向量相减,则其大小应该为 1。
  • 求反射向量与从交点到观察者的向量的点积,我们称之为“sF”。
  • 最后,我们将对象的颜色称为“clr”,最终颜色将称为“fClr”。
  • 要获得最终颜色,请使用以下公式: fClr = Ka(clr) + Kd(因子)(clr) + Ks(specularFactor^n)(clr)
  • 最后,我检查您的 R、G 或 B 值是否超出范围。如果是这种情况,请使 R、G 或 B 值等于最接近的界限。

**如果您使用的是 RGB,请为每个 RGB 值执行公式。

**我想指出,所有 RGB 值都应该是 0.0 - 1.0 的标量。如果您使用的是 8 位 RGB (0-255),请先将这些值除以 255,然后再将它们放入等式中,然后将输出值乘以 255。

**任何时候我提到一个向量,它都应该是一个单位向量,也就是说,它的大小应该是1。

我希望这会有所帮助!祝你好运!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-11-11
    • 1970-01-01
    • 2017-08-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-05-31
    • 2016-06-14
    相关资源
    最近更新 更多