英文:
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 < 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;
}
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 <= 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 < 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;
}
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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论