10

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

(不要介意愚蠢的代码,我只是想先让原则正确)。

这是它的外观:

在此处输入图像描述

这里只是漫反射分量:

在此处输入图像描述

这里只是镜面反射分量:

在此处输入图像描述

编辑:将漫反射更改为颜色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];
4

4 回答 4

7

问题是,当您计算球体的漫反射颜色时,您已经有一小块像素区域为 1 或非常接近 1(在绿色通道中)。将“phong”分量(在所有通道中的值接近 1)相加,得到 >= 1 的像素区域。然后将颜色值钳制为 1 时,>=1 的区域代表出去。

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

您可以通过多种措施避免该问题:

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

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


更新1:

我注意到一件事,当您对输出图像进行伽玛校正时 - 效果不太明显;) - 好吧,这有点不完整。

最终的解决方案是进行物理正确或仅使用另一种着色模型:Wikipedia on Specular highlight


更新 2:

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

float diffuseContrib = 1.f - mySpec;

那应该看起来不错,但我不确定它实际上有多正确:)。

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

我的结果看起来是这样的:

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

于 2013-03-25T16:51:27.890 回答
6

这一直是“镜面 + 漫反射 + 环境”照明模型的问题。也就是说,它是一种黑客攻击,因此不能保证正确性。

如果您如此热衷于首先巩固您的基础知识,请查看 Matt Pharr 和 Greg Humphreys 的优秀书籍“基于物理的光线追踪”。

于 2013-03-25T21:20:57.117 回答
1

为什么不做(光+环境)*漫反射+镜面反射?即在将光照和阴影与漫反射相乘后添加镜面反射分量?这将给出明确的亮点。

于 2014-03-01T21:50:16.070 回答
1

您应该阅读Blinn/Phong 模型。这里有一些示例着色器片段代码。基本上,您使用它们各自的角度缩放单个组件(环境、漫反射、镜面反射项)并将它们相加。

varying vec3 N;
varying vec3 v;    
void main (void)  
{  
   vec3 L = normalize(gl_LightSource[0].position.xyz - v);   
   vec3 E = normalize(-v); // we are in Eye Coordinates, so EyePos is (0,0,0)  
   vec3 R = normalize(-reflect(L,N));  

   //calculate Ambient Term:  
   vec4 Iamb = gl_FrontLightProduct[0].ambient;    

   //calculate Diffuse Term:  
   vec4 Idiff = gl_FrontLightProduct[0].diffuse * max(dot(N,L), 0.0);
   Idiff = clamp(Idiff, 0.0, 1.0);     

   // calculate Specular Term:
   vec4 Ispec = gl_FrontLightProduct[0].specular 
                * pow(max(dot(R,E),0.0),0.3*gl_FrontMaterial.shininess);
   Ispec = clamp(Ispec, 0.0, 1.0); 
   // write Total Color:  
   gl_FragColor = gl_FrontLightModelProduct.sceneColor + Iamb + Idiff + Ispec;     
}

取自:http ://www.opengl.org/sdk/docs/tutorials/ClockworkCoders/lighting.php

于 2013-08-28T18:10:47.820 回答