光栅化器纹理调试求助:如何实现清晰完整的纹理覆盖?
从你描述的「网格完整但纹理效果差」的情况,结合提供的扫描线渲染代码来看,问题大概率出在纹理坐标的透视校正插值逻辑上。下面是具体的分析和可落地的修复建议:
1. 透视校正插值逻辑错误(最可能的根源)
在3D光栅化中,屏幕空间的线性插值会产生透视畸变——远处纹理被拉伸、近处被压缩,必须对UV坐标做透视校正才能得到正确的纹理映射。
看你代码里的纹理计算:
vector2D texture = ((uvOne * u) * wOne + (uvTwo * v) * wTwo + (uvThree * w) * wThree) / corrW;
这里的逻辑完全搞反了!假设wOne/wTwo/wThree是顶点的1/z值(这是透视校正的常规做法),正确的计算步骤应该是:
- 先将每个顶点的UV坐标除以该顶点的z值(等价于乘以
1/z) - 对这些值进行线性插值
- 最后除以插值后的
1/z值(也就是你的corrW)
修正后的代码:
vector2D texture( (u * uvOne.vecOrigin[0] / wOne + v * uvTwo.vecOrigin[0] / wTwo + w * uvThree.vecOrigin[0] / wThree) / corrW, (u * uvOne.vecOrigin[1] / wOne + v * uvTwo.vecOrigin[1] / wTwo + w * uvThree.vecOrigin[1] / wThree) / corrW );
如果wOne/wTwo/wThree是顶点的z值而非1/z,请先取倒数:1.0f / vertexOne.vecOrigin[2],再代入上述计算。
2. 重心坐标的正确性验证
确保你的barycentric函数返回的u/v/w是符合要求的重心权重(满足u + v + w = 1)。可以加一段调试逻辑:当像素坐标恰好落在某个顶点上时,输出对应的权重值——比如落在vertexOne上时,u应该接近1,v和w接近0。如果重心坐标错误,所有基于它的插值(纹理、法线、颜色)都会失效。
3. 纹理坐标的范围与采样处理
- 检查
fragments函数的采样逻辑:如果UV坐标超出[0,1]范围,是否做了正确处理?比如用clamp限制到[0,1],或者设置重复采样。超出范围的UV会采样到纹理图像外的无效像素,导致颜色混乱。 - 你代码里对V坐标做了翻转:
1 - texture.vecOrigin[1],这是合理的(多数图像格式Y轴从上到下,而3D模型V坐标通常从下到上),但可以确认下纹理图像的存储方向是否匹配,避免不必要的翻转错误。
4. 法线与漫反射颜色的插值优化
虽然这不是纹理问题的直接原因,但你的法线和漫反射颜色插值也存在同样的透视校正问题,建议同步修正:
// 法线的透视校正插值 vector3D normal( (u * normOne.vecOrigin[0] / wOne + v * normTwo.vecOrigin[0] / wTwo + w * normThree.vecOrigin[0] / wThree) / corrW, (u * normOne.vecOrigin[1] / wOne + v * normTwo.vecOrigin[1] / wTwo + w * normThree.vecOrigin[1] / wThree) / corrW, (u * normOne.vecOrigin[2] / wOne + v * normTwo.vecOrigin[2] / wTwo + w * normThree.vecOrigin[2] / wThree) / corrW ); // 漫反射颜色的透视校正插值 vector3D diff( (u * diffColorOne.vecOrigin[0] / wOne + v * diffColorTwo.vecOrigin[0] / wTwo + w * diffColorThree.vecOrigin[0] / wThree) / corrW, (u * diffColorOne.vecOrigin[1] / wOne + v * diffColorTwo.vecOrigin[1] / wTwo + w * diffColorThree.vecOrigin[1] / wThree) / corrW, (u * diffColorOne.vecOrigin[2] / wOne + v * diffColorTwo.vecOrigin[2] / wTwo + w * diffColorThree.vecOrigin[2] / wThree) / corrW );
5. 深度测试的细节检查
虽然你提到网格完整,但还是建议确认zDepth数组的初始值是否设为远平面的最大值(比如FLT_MAX),这样当zPixel更小(更靠近相机)时才会更新像素。如果初始值设反了,会导致部分像素被错误丢弃。
优先修复透视校正的插值逻辑,这是绝大多数纹理渲染异常的核心原因。如果修复后仍有问题,可以进一步排查纹理采样和重心坐标的正确性。
内容的提问来源于stack exchange,提问作者Jonas Nacken Hansson

