Java:光线追踪:光泽反射着色

Java: Ray Tracing: Glossy reflection coloring

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

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

我现在计算颜色的方法是从后到前平均反射表面和新撞击表面的颜色。因此光线较早到达的表面颜色比后来的表面颜色表现得更多。

如果颜色 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

也许只有我一个人如此,但 none 这些倒影看起来非常逼真。我用作指南的是 Cornell 的 powerpoint,除其他外,确实提到了有关添加颜色的任何内容。镜子确实有一定程度的颜色,我不知道混合颜色的正确方法。我做错了什么?

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

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

为了获得交点的颜色,我调用了 getColor() 方法,该方法获取交点的矢量(我如何存储 3d 点)。我用它来确定表面的未着色颜色。如果表面没有纹理并且只是空白颜色(如上面的形状),则返回未着色的颜色(这只是存储在每个形状 classes "Color c = Color.RED" 中)。例如 Color.RED

我采用该颜色并以递归方式将其作为基色插入到 MasterLight 中,以获得阴影,就好像表面是法线和环境光一样。此过程 returns 形状通常具有的阴影。现在 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),这样最暗的 a颜色可以是其原始亮度的 0.2)。

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

反射的每次迭代都会使用最新的表面颜色调用 addColor。详细来说,如果(在上图中)一条光线刚刚从平面反弹并击中一个球体并反弹到空 space,我首先找到球体表面在反弹点的颜色,它是 'c' 的设置。然后我用交点处的平面颜色调用 addColor(第一次)。

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

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

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

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

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

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

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

  • 对于场景中的任何对象,定义三个常量:Ka(环境光)、Kd(漫射光)和 Ks(镜面光)。我们还将为您的对象的光泽度定义一个常量 "n"。我会将此值保持在 3 以上。
  • 求法向量和光向量的点积,我们暂时称这个量为"dF"。
  • 现在我们来计算反射向量:它是法向量,乘以法向量和光向量的点积,再乘以二。减去光向量,如果法向量和光向量都减去光向量,则它的幅度应该为 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。

希望对您有所帮助!祝你好运!