一、先搞懂:视差映射为啥会出“凹坑”
1.1 啥是视差映射
你可以想象自己站在一面刷了砖纹的墙上,要是真的每块砖都凸起来,得做很多建模,太费性能。视差映射就像给墙面加了一层“假凹凸滤镜”——用一张黑白图(高度图)记录哪里高哪里低,渲染时模拟光线从高低处的反射效果,让平面看起来有凹凸纹理。但很多人做的时候,墙面会莫名出现小凹坑,明明高度图里没画,这就是我们要解决的问题。
1.2 最常见的“错误凹陷”长啥样
比如做了个走廊的墙,铺了砖纹,结果某块砖的右下角突然陷进去一个小坑,或某条砖缝左右两边高度对不上,看起来像破了洞。这些凹陷不是建模的问题,而是渲染时两个核心环节出错:一是定位凹凸的坐标方向歪了,二是采样高度图时拿错了细节。
二、核心元凶:切线空间的“姿势”错了
2.1 切线空间是啥
别听名字吓人,其实就是给你站的那一小块墙面定个“专属坐标系”:你的右手方向是切线,对应纹理的左右;你头顶的方向是副切线,对应纹理的上下;你的正面(垂直墙面)是法线方向,对应凹凸的深浅。所有高度图的采样,都得在这个坐标系里转对方向,不然就会跑偏。
2.2 切线空间算错会导致啥问题
比如做走廊时,模型的UV展开没对齐——本来一块砖的UV应该是正方形,结果被拉成长条,这时候算切线和副切线就会歪掉,像人站在斜坡上站不稳,坐标方向偏了。采样高度图时就会跑到砖外甚至墙外面,采样到其他地方的颜色,出现不该有的凹坑。下面是错误的切线空间处理示例:
// 错误版本的视差映射GLSL shader
varying vec2 vUv;
varying mat3 vTBN; // 切线空间矩阵,此处切/副切线未正交,方向错误
uniform sampler2D heightMap;
uniform float heightScale;
void main() {
// 错误:直接用模型空间坐标采样,未转换到切线空间,偏移方向偏离纹理
float height = texture2D(heightMap, vUv).r;
vec2 parallaxOffset = (height - 0.5) * heightScale * vTBN[2].xy;
vec2 parallaxUv = vUv + parallaxOffset;
// 错误:使用最近邻采样,会产生高度跳变
gl_FragColor = texture2D(heightMap, parallaxUv);
}
三、第二个坑:高度图采样的“精度不够”
3.1 采样精度差为啥会出凹陷
高度图一般是小尺寸的纹理(比如256×256像素),如果采样用“最近邻插值”,就是每次只取离计算点最近的那个像素的颜色,当视差偏移刚好在两个像素中间时,就会突然跳到另一个像素,高度瞬间变低,看起来像个小凹坑,就像看像素图放大后的锯齿边缘。
3.2 怎么调采样精度
要把采样方式换成“双线性插值”,就是取计算点周围四个像素的颜色,按距离加权平均,过渡就自然了,不会有突然的跳变。就像看照片放大后边缘仍是平滑的,而非锯齿。另外要注意高度图的尺寸,别用太小的,至少512×512,细节会更清晰。下面是修正后的采样代码:
// 正确版本的视差映射GLSL shader
varying vec2 vUv;
varying mat3 vTBN; // 切线空间矩阵,此处切/副切线严格正交,方向正确
uniform sampler2D heightMap;
uniform float heightScale;
void main() {
// 修正:用切线空间方向计算视差偏移,确保偏移方向与纹理对齐
float height = texture2D(heightMap, vUv).r;
vec2 tangentDir = normalize(vTBN[0].xy); // 切线方向,对应纹理左右
vec2 bitangentDir = normalize(vTBN[1].xy); // 副切线方向,对应纹理上下
vec2 parallaxOffset = (height - 0.5) * heightScale * tangentDir;
vec2 parallaxUv = vUv + parallaxOffset;
// 修正:使用双线性插值采样,避免高度跳变
float correctedHeight = texture2D(heightMap, parallaxUv).r;
gl_FragColor = vec4(vec3(parallaxUv, correctedHeight), 1.0);
}
四、实战检验方法:2步搞定凹陷问题
4.1 应用场景与技术特点
该技术适用于手游3D纹理、网页3D画廊、3D建模纹理预览等,凡是用视差映射做凹凸效果的场景都适用。优点是无需额外建模,节省性能,移动端也能流畅运行;缺点是对UV展开和采样设置要求高,小细节容易出问题。注意事项:1. UV展开要规整,不能拉伸;2. 高度图采样必须用双线性插值;3. 高度缩放参数不能太大,不然偏移会超出纹理范围;4. 调试时可打印切线空间矩阵,检查切/副切线是否正交。
4.2 排查与修复步骤
第一步:先检查切线空间,计算切和副切线的点积,若接近0说明正交,排除切线空间问题;若点积偏大,说明矩阵计算错误,重新调整切线空间矩阵的生成逻辑。第二步:切换高度图的采样方式,从最近邻改成双线性,若凹陷消失,说明是采样精度问题,适当增大高度图尺寸即可;若未消失,再排查切线空间的方向设置。
五、总结
视差映射出现错误凹陷,本质是两个核心环节的问题:一是定位凹凸的切线空间坐标系歪了,导致采样方向出错;二是高度图采样时用了低精度的插值,导致高度跳变。只要把这两个地方严格检查,就能搞定大部分凹陷问题。遇到这类问题不用慌,从坐标系和采样精度入手一步步排查,就能快速找到病根。
评论
围绕“视差映射表面出现错误凹陷?切线空间计算与高度图采样精度的严格检验方法”参与讨论