光线追踪器非常嘈杂

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

Ray tracer very noisy

问题

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

着色器代码:

光线与球体的相交检测:

HitInfo testSphereIntersect(vec3 rayOrigin, vec3 rayDir, Sphere s) {
  HitInfo h;
  h.didHit = true;

  vec3 translatedRayOrig = rayOrigin - s.position.xyz;

  float a = dot(rayDir, rayDir);
  float b = dot(translatedRayOrig, rayDir) * 2;
  float c = dot(translatedRayOrig, translatedRayOrig) - (s.radius * s.radius);

  float discriminant = (b * b) - (4 * a * c);

  if (discriminant < 0) {
    h.didHit = false;
    return h;
  }

  float t_0 = (-b - sqrt(discriminant)) / (2 * a);
  float t_1 = (-b + sqrt(discriminant)) / (2 * a);

  if (t_0 < 0 && t_1 < 0) {
    h.didHit = false;
    return h;
  }

  h.rayT = t_0 >= 0 ? t_0 : t_1;
  h.position = rayOrigin + rayDir * h.rayT;
  h.normal = normalize(h.position - s.position.xyz);

  return h;
}

跟踪函数:

vec4 trace(vec3 rayDir, vec4 bgColour){

  vec3 rayOrigin = cameraPos;

  vec3 colour = vec3(0, 0, 0);

  HitInfo hit;
  uint sphereIndex;

  Material mat;
  float mult = 1.0f;

  for (int i = 0; i <= maxBounces; i++){
    
    hit = closestHit(sphereIndex, rayDir, rayOrigin);
    if (!hit.didHit){
      
      colour +=  bgColour.xyz * mult;
      break;
    }

    vec3 lightDir = normalize(vec3(-1, -1, -1));
    float intensity = max(dot(hit.normal, -lightDir), 0);

    mat = materials[spheres[sphereIndex].materialID];

    vec3 sphereCol = mat.kd.xyz;
    sphereCol *= intensity;
    colour += sphereCol * mult;

    rayOrigin = hit.position;
    rayDir = normalize(reflect(rayDir, hit.normal));

    mult *= 0.7f;
  }

  return vec4(colour, 1);
}

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

HitInfo closestHit(out uint index, vec3 rayDir, vec3 rayOrigin){

  HitInfo minHit;
  minHit.rayT = 1.0 / 0.0;
  minHit.didHit = false;

  uint minIndex = -1;
  
  for (int i = 0; i < spheres.length(); i++){

    HitInfo h = testSphereIntersect(rayOrigin, rayDir, spheres[i]);
    if (!h.didHit)
      continue;

    if (h.rayT < minHit.rayT){
      minHit = h;
      minIndex = i;
      minHit.didHit = true;
    }
  }
  
  index = minIndex;
  return minHit;
}

以下是光线生成代码:

vec3 getRayDir(float fov /* in degrees */, float aspectRatio) {
  vec2 texelCoord = gl_GlobalInvocationID.xy;
  vec2 ndc = vec2((texelCoord.x + 0.5) / (resolution[0]),
                  (texelCoord.y + 0.5) / (resolution[1]));

  vec2 pixelCamera;
  pixelCamera.x = ((2 * ndc.x) - 1) * aspectRatio * tan(radians(fov / 2));
  pixelCamera.y = ((2 * ndc.y) - 1) * tan(radians(fov / 2));

  vec3 rayDir = normalize((lookAt * vec4(pixelCamera, -1.0f, 0)).xyz);

  return rayDir;
}
英文:

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:

HitInfo testSphereIntersect(vec3 rayOrigin, vec3 rayDir, Sphere s) {
  HitInfo h;
  h.didHit = true;

  vec3 translatedRayOrig = rayOrigin - s.position.xyz;

  float a = dot(rayDir, rayDir);
  float b = dot(translatedRayOrig, rayDir) * 2;
  float c = dot(translatedRayOrig, translatedRayOrig) - (s.radius * s.radius);

  float discriminant = (b * b) - (4 * a * c);

  if (discriminant &lt; 0) {
    h.didHit = false;
    return h;
  }

  float t_0 = (-b - sqrt(discriminant)) / (2 * a);
  float t_1 = (-b + sqrt(discriminant)) / (2 * a);

  if (t_0 &lt; 0 &amp;&amp; t_1 &lt; 0) {
    h.didHit = false;
    return h;
  }

  h.rayT = t_0 &gt;= 0 ? t_0 : t_1;
  h.position = rayOrigin + rayDir * h.rayT;
  h.normal = normalize(h.position - s.position.xyz);

  return h;
}

The trace function:

vec4 trace(vec3 rayDir, vec4 bgColour){

  vec3 rayOrigin = cameraPos;

  vec3 colour = vec3(0, 0, 0);

  HitInfo hit;
  uint sphereIndex;

  Material mat;
  float mult = 1.0f;

  for (int i = 0; i &lt;= maxBounces; i++){
    
    hit = closestHIt(sphereIndex, rayDir, rayOrigin);
    if (!hit.didHit){
      
      colour +=  bgColour.xyz * mult;
      break;
    }

    vec3 lightDir = normalize(vec3(-1, -1, -1));
    float intensity = max(dot(hit.normal, -lightDir), 0);

    mat = materials[spheres[sphereIndex].materialID];

    vec3 sphereCol = mat.kd.xyz;
    sphereCol *= intensity;
    colour += sphereCol * mult;

    rayOrigin = hit.position;
    rayDir = normalize(reflect(rayDir, hit.normal));

    mult *= 0.7f;
  }

  return vec4(colour, 1);
}

This finds the closes hit:

HitInfo closestHIt(out uint index, vec3 rayDir, vec3 rayOrigin){

  HitInfo minHit;
  minHit.rayT = 1.0 / 0.0;
  minHit.didHit = false;

  uint minIndex = -1;
  
  for (int i = 0; i &lt; spheres.length(); i++){

    HitInfo h = testSphereIntersect(rayOrigin, rayDir, spheres[i]);
    if (!h.didHit)
      continue;

    

    if (h.rayT &lt; minHit.rayT){
      minHit = h;
      minIndex = i;
      minHit.didHit = true;
    }
  }
  
  index = minIndex;
  return minHit;
}

And here is the ray generation code:

vec3 getRayDir(float fov /* in degrees */, float aspectRatio) {
  vec2 texelCoord = gl_GlobalInvocationID.xy;
  vec2 ndc = vec2((texelCoord.x + 0.5) / (resolution[0]),
                  (texelCoord.y + 0.5) / (resolution[1]));

  vec2 pixelCamera;
  pixelCamera.x = ((2 * ndc.x) - 1) * aspectRatio * tan(radians(fov / 2));
  pixelCamera.y = ((2 * ndc.y) - 1) * tan(radians(fov / 2));


  vec3 rayDir = normalize((lookAt * vec4(pixelCamera, -1.0f, 0)).xyz);

  return rayDir;
}

答案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:

确定