光线追踪器非常嘈杂

huangapple go评论157阅读模式
英文:

Ray tracer very noisy

问题

我正在实现一个光线追踪器。它运行在一个计算着色器内,将结果写入纹理。渲染器使用完美反射,即没有随机性。理论上不应该有噪音源。然而,实际上渲染的图像非常嘈杂。我对为什么会出现这种情况一无所知。

着色器代码:

光线与球体的相交检测:

  1. HitInfo testSphereIntersect(vec3 rayOrigin, vec3 rayDir, Sphere s) {
  2. HitInfo h;
  3. h.didHit = true;
  4. vec3 translatedRayOrig = rayOrigin - s.position.xyz;
  5. float a = dot(rayDir, rayDir);
  6. float b = dot(translatedRayOrig, rayDir) * 2;
  7. float c = dot(translatedRayOrig, translatedRayOrig) - (s.radius * s.radius);
  8. float discriminant = (b * b) - (4 * a * c);
  9. if (discriminant < 0) {
  10. h.didHit = false;
  11. return h;
  12. }
  13. float t_0 = (-b - sqrt(discriminant)) / (2 * a);
  14. float t_1 = (-b + sqrt(discriminant)) / (2 * a);
  15. if (t_0 < 0 && t_1 < 0) {
  16. h.didHit = false;
  17. return h;
  18. }
  19. h.rayT = t_0 >= 0 ? t_0 : t_1;
  20. h.position = rayOrigin + rayDir * h.rayT;
  21. h.normal = normalize(h.position - s.position.xyz);
  22. return h;
  23. }

跟踪函数:

  1. vec4 trace(vec3 rayDir, vec4 bgColour){
  2. vec3 rayOrigin = cameraPos;
  3. vec3 colour = vec3(0, 0, 0);
  4. HitInfo hit;
  5. uint sphereIndex;
  6. Material mat;
  7. float mult = 1.0f;
  8. for (int i = 0; i <= maxBounces; i++){
  9. hit = closestHit(sphereIndex, rayDir, rayOrigin);
  10. if (!hit.didHit){
  11. colour += bgColour.xyz * mult;
  12. break;
  13. }
  14. vec3 lightDir = normalize(vec3(-1, -1, -1));
  15. float intensity = max(dot(hit.normal, -lightDir), 0);
  16. mat = materials[spheres[sphereIndex].materialID];
  17. vec3 sphereCol = mat.kd.xyz;
  18. sphereCol *= intensity;
  19. colour += sphereCol * mult;
  20. rayOrigin = hit.position;
  21. rayDir = normalize(reflect(rayDir, hit.normal));
  22. mult *= 0.7f;
  23. }
  24. return vec4(colour, 1);
  25. }

这是找到最近的交点的函数:

  1. HitInfo closestHit(out uint index, vec3 rayDir, vec3 rayOrigin){
  2. HitInfo minHit;
  3. minHit.rayT = 1.0 / 0.0;
  4. minHit.didHit = false;
  5. uint minIndex = -1;
  6. for (int i = 0; i < spheres.length(); i++){
  7. HitInfo h = testSphereIntersect(rayOrigin, rayDir, spheres[i]);
  8. if (!h.didHit)
  9. continue;
  10. if (h.rayT < minHit.rayT){
  11. minHit = h;
  12. minIndex = i;
  13. minHit.didHit = true;
  14. }
  15. }
  16. index = minIndex;
  17. return minHit;
  18. }

以下是光线生成代码:

  1. vec3 getRayDir(float fov /* in degrees */, float aspectRatio) {
  2. vec2 texelCoord = gl_GlobalInvocationID.xy;
  3. vec2 ndc = vec2((texelCoord.x + 0.5) / (resolution[0]),
  4. (texelCoord.y + 0.5) / (resolution[1]));
  5. vec2 pixelCamera;
  6. pixelCamera.x = ((2 * ndc.x) - 1) * aspectRatio * tan(radians(fov / 2));
  7. pixelCamera.y = ((2 * ndc.y) - 1) * tan(radians(fov / 2));
  8. vec3 rayDir = normalize((lookAt * vec4(pixelCamera, -1.0f, 0)).xyz);
  9. return rayDir;
  10. }
英文:

So, I'm implementing a ray tracer. It runs inside a compute shader which writes the result onto a texture. The renderer uses perfect reflections, that is, there is no randomness. So, ideally, there should be no source of noise. However, the rendered image is, in fact, extremely noisy. I am clueless as to why this should be the case.

The shader code:

Ray-sphere intersection:

  1. HitInfo testSphereIntersect(vec3 rayOrigin, vec3 rayDir, Sphere s) {
  2. HitInfo h;
  3. h.didHit = true;
  4. vec3 translatedRayOrig = rayOrigin - s.position.xyz;
  5. float a = dot(rayDir, rayDir);
  6. float b = dot(translatedRayOrig, rayDir) * 2;
  7. float c = dot(translatedRayOrig, translatedRayOrig) - (s.radius * s.radius);
  8. float discriminant = (b * b) - (4 * a * c);
  9. if (discriminant &lt; 0) {
  10. h.didHit = false;
  11. return h;
  12. }
  13. float t_0 = (-b - sqrt(discriminant)) / (2 * a);
  14. float t_1 = (-b + sqrt(discriminant)) / (2 * a);
  15. if (t_0 &lt; 0 &amp;&amp; t_1 &lt; 0) {
  16. h.didHit = false;
  17. return h;
  18. }
  19. h.rayT = t_0 &gt;= 0 ? t_0 : t_1;
  20. h.position = rayOrigin + rayDir * h.rayT;
  21. h.normal = normalize(h.position - s.position.xyz);
  22. return h;
  23. }

The trace function:

  1. vec4 trace(vec3 rayDir, vec4 bgColour){
  2. vec3 rayOrigin = cameraPos;
  3. vec3 colour = vec3(0, 0, 0);
  4. HitInfo hit;
  5. uint sphereIndex;
  6. Material mat;
  7. float mult = 1.0f;
  8. for (int i = 0; i &lt;= maxBounces; i++){
  9. hit = closestHIt(sphereIndex, rayDir, rayOrigin);
  10. if (!hit.didHit){
  11. colour += bgColour.xyz * mult;
  12. break;
  13. }
  14. vec3 lightDir = normalize(vec3(-1, -1, -1));
  15. float intensity = max(dot(hit.normal, -lightDir), 0);
  16. mat = materials[spheres[sphereIndex].materialID];
  17. vec3 sphereCol = mat.kd.xyz;
  18. sphereCol *= intensity;
  19. colour += sphereCol * mult;
  20. rayOrigin = hit.position;
  21. rayDir = normalize(reflect(rayDir, hit.normal));
  22. mult *= 0.7f;
  23. }
  24. return vec4(colour, 1);
  25. }

This finds the closes hit:

  1. HitInfo closestHIt(out uint index, vec3 rayDir, vec3 rayOrigin){
  2. HitInfo minHit;
  3. minHit.rayT = 1.0 / 0.0;
  4. minHit.didHit = false;
  5. uint minIndex = -1;
  6. for (int i = 0; i &lt; spheres.length(); i++){
  7. HitInfo h = testSphereIntersect(rayOrigin, rayDir, spheres[i]);
  8. if (!h.didHit)
  9. continue;
  10. if (h.rayT &lt; minHit.rayT){
  11. minHit = h;
  12. minIndex = i;
  13. minHit.didHit = true;
  14. }
  15. }
  16. index = minIndex;
  17. return minHit;
  18. }

And here is the ray generation code:

  1. vec3 getRayDir(float fov /* in degrees */, float aspectRatio) {
  2. vec2 texelCoord = gl_GlobalInvocationID.xy;
  3. vec2 ndc = vec2((texelCoord.x + 0.5) / (resolution[0]),
  4. (texelCoord.y + 0.5) / (resolution[1]));
  5. vec2 pixelCamera;
  6. pixelCamera.x = ((2 * ndc.x) - 1) * aspectRatio * tan(radians(fov / 2));
  7. pixelCamera.y = ((2 * ndc.y) - 1) * tan(radians(fov / 2));
  8. vec3 rayDir = normalize((lookAt * vec4(pixelCamera, -1.0f, 0)).xyz);
  9. return rayDir;
  10. }

答案1

得分: -1

我借助这个回答解决了它:https://stackoverflow.com/a/35742512/18092120

显然,光线起始点离表面太近了,所以我所需要做的就是在反射光线的方向上微微偏移它。

英文:

I solved it with the help of this answer: https://stackoverflow.com/a/35742512/18092120

Apparently, the ray was starting too close to the surface, so all I had to do was offset it by a tiny amount in the direction of the reflected ray.

huangapple
  • 本文由 发表于 2023年7月10日 18:08:40
  • 转载请务必保留本文链接:https://go.coder-hub.com/76652714.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定