自己的渲染器也会遇上类似的问题。
后来上别人的仓库提了个issue,没想到是个typical question(又向歪果仁暴露了自己图形基础不扎实的事实)。原回答如下:
That is a usual artifact when rendering low-poly models with interpolated per-vertex shading normals.
At high geometry curvatures, which appear along the silhouettes of this object, it can happen that the interpolated shading normal across a triangle primitive actually doesn’t lie inside the same hemisphere as the direction to the viewer (negative ray direction) and that’s a false condition for the lighting test. For the shading calculation that’s like looking at the backface of an opaque object. (This would not happen when using the face-normals instead of the shading normals, but then you get a facetted look.)
Similar effects would arise when the sampled continuation ray in a path tracer would continue below the geometric surface of opaque materials, which also happens regularly with bump- or normal-maps.
This site has some nice images explaining interpolated shading normals: scratchapixel.com/lessons/3d-basic-rendering/introduction-to-shading/shading-normals
The black areas are running into the dot(V, N) < 0.0 case.
it’s know topic with possible mitigation stragegies as per the publication “Consistent Normal Interpolation”, Reshetov et al., 2010 blog.yiningkarlli.com/2015/01/consistent-normal-interpolation.html and an implementation here
解释一下。
首先,我们做渲染时,一般会用插值的方法得到面片内某一点的法线。具体来说,我们shoot了一根ray,这根ray打到了一个三角形面片上的一个点。我们可以得到三角形三个顶点的法线和hit point的重心坐标,进而就可以插值出hit point的法线,一般管它叫shading normal。
这里会有一个问题,我们shoot出的ray打到了三角形面片,那我们其实是可以看到三角形面片上的所有点的,因为dot(viewDir, faceNormal)>0
。但实际上在渲染时,我们会把某些点视为不可见,因为测试可见性的条件为dot(viewDir, shadingNormal)>0
。如下图(灵魂画师):
我们射出的ray(viewDir=-rayDir
),打到了一个三角形面片上的点,和三角形的相交测试是使用face normal的,dot(faceNormal, viewDir)>0
。但我们插值出来的shading normal,又会出现dot(shadingNormal, viewDir)<0
的情况,进一步我们就不会在这个点上做光照计算,因此这块最后的颜色就黑了。
上面那篇siggraph asia的文章对这个问题提出了缓解办法。但我试过了,效果并不好。其实最简单的做法就是用face normal来做光照计算的测试,但这样最后渲染出来会有很强的面片效应。
我已经放弃了对这个artifact进行进一步解决(摆烂ing)。