光线追踪 - 如何结合漫反射和镜面反射颜色?

OMH*_*OMH 10 3d graphics raytracing

我一直在阅读有关光线追踪和阴影的大量文章,但我的光线追踪图像看起来并不太好.我在谈论镜面高光附近非常明亮的绿色区域.结果绿色在这里最大化,看起来像.如何调整颜色和/或阴影计算以使其看起来正确?

(别担心愚蠢的代码,我只是想先把原则弄清楚).

以下是它的外观:

在此输入图像描述

这里只是漫反射组件:

在此输入图像描述

这是仅镜面反射分量:

在此输入图像描述

编辑:将漫反射更改为颜色diffuseColor = ColorMake(0.0f,0.6f,0.0f); 然后图像看起来像这样:

在此输入图像描述

Point lightPosition = PointMake(-100.0f, 100.0f, -100.0f);
Color diffuseColor  = ColorMake(0.0f, 1.0f, 0.0f);
Color specularColor = ColorMake(1.0f, 1.0f, 1.0f);
Color pixelColor    = ColorMake(0.0f, 0.0f, 0.0f);

//  Trace...

            // Diffuse
            Point intersectionPosition = PointMake(x, y, z);
            Vector intersectionNormal = VectorMake((x - xs) / rs, (y - ys) / rs, (z - zs) / rs);
            Vector intersectionNormalN = VectorNormalize(intersectionNormal);
            Vector lightVector          = VectorSubtract(lightPosition, intersectionPosition);
            VectorlightVectorN         = VectorNormalize(lightVector);
            float      cosTheta        = VectorDotProduct(intersectionNormalN, lightVectorN);
            if (cosTheta < 0.0f)
            {
                cosTheta = 0.0f;
            }

            pixelColor = ColorMultScalar(diffuseColor, cosTheta);

            // Specular
            Vector incomVector    = VectorSubtract(intersectionPosition, lightPosition);
            Vector incomVectorN   = VectorNormalize(incomVector);

            float myDot = - VectorDotProduct(incomVectorN, intersectionNormalN);
            float myLen = 2.0f * myDot;

            Vector tempNormal     = VectorMultScalar(intersectionNormalN, myLen);
            Vector reflectVector  = VectorAdd(tempNormal, incomVectorN);
            Vector reflectVectorN = VectorNormalize(reflectVector);

            float mySpec = MAX(-VectorDotProduct(reflectVectorN, incomVectorN), 0);
            mySpec       = powf(mySpec, 5);

            specularColor = ColorMultScalar(specularColor, mySpec);
            pixelColor    = ColorAdd(pixelColor, specularColor);
            pixelColor    = ColorClamp(pixelColor);

            [self putPixelatX:i andY:j andR:pixelColor.r andG:pixelColor.g andB:pixelColor.b];
Run Code Online (Sandbox Code Playgroud)

Mar*_*gen 7

问题是,当你计算球体的漫反射颜色时,你已经有一个1或非常接近1的小像素区域(在绿色通道中).将"phong"组件(其所有通道中的值接近1)相加,得到> = 1的像素区域.然后将颜色值钳位为1时,> = 1的区域代表出.

您可以使用图片编辑程序对此进行测试,并对两个图层(漫反射层上方的phong图层)进行"添加"叠加.这给出了您看到的结果 - 以及预期的结果.

您可以通过以下措施避免此问题:

  1. 您可以将光源调暗一点,即将由余弦计算出的漫射强度乘以亮度 - 即0.8或0.7.
  2. 您可以限制球体的颜色饱和度(绿色),使其不那么绿;)
  3. 使用色调映射运算符将像素的颜色值标准化为[0..1]范围 - 但该主题非常广泛 - 维基百科可能会给出一个很好的介绍.你甚至不需要全力以赴,因为非基于物理的渲染更简单的色调映射运算符可能就足够了并产生令人愉悦的结果.

我的光线追踪实验可以追溯到几年前,但你可以尝试这些东西.


更新1:

有一点我注意到,当你对你的输出图像进行伽马校正时 - 效果不那么明显;) - 好吧,这有点不完整.

最终的解决方案是使用另一种着色模型:或者使用另一种着色模型:维基百科的镜面高光.


更新2:

一个实际的解决方案是计算最终像素颜色的phong贡献(即你的变量mySpec).我的想法是只使用漫反射组件的一部分,其中镜面反射实际上不是0,也就是说,如果你有一些镜面反射组件,你实际上并没有看到漫反射组件太多(或根本没有)所以它可以是调整为:

float diffuseContrib = 1.f - mySpec;
Run Code Online (Sandbox Code Playgroud)

这应该看起来不错,但我不确定它实际上是多么正确 :).

但请注意; 这假设您的镜面反射和漫反射分量在[0..1]范围内.

我的结果看起来像这样:

使用镜面反射贡献计算的漫反射贡献


Rah*_*jee 6

这一直是"镜面+漫反射+环境"照明模型的问题.即,它是一个黑客,因此,不保证正确性.

如果你非常热衷于巩固你的基础知识,请看看Matt Pharr和Greg Humphreys的优秀书籍"基于物理的光线追踪".