You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于GLSL-ES的边缘着色器部分边缘不显示问题求助

修复GLSL-ES边缘着色器部分边缘不显示的问题

嘿,我瞅了你的代码和问题描述,你遇到的部分视角边缘消失的问题,根源出在对法线的投影矩阵分量缩放处理上,咱们一步步来理清楚:

问题分析

你的代码里直接用projection_matrix[2][3]和projection_matrix[3][2]来缩放法线的y、x分量,这俩值在不同投影类型(比如透视/正交)下差异极大,而且这种硬编码取投影矩阵分量的方式,会导致某些视角下法线方向被扭曲,进而让顶点偏移的方向或幅度出现问题——要么偏移量太小看不见,要么偏移方向反了导致边缘被模型本身遮挡,最终就出现了部分边缘消失的情况。

另外,你当前的偏移计算只是简单基于变换后顶点位置做减法,没有结合法线与视线的夹角判断边缘,逻辑稳定性不足。

修正方案

咱们换一种更可靠的思路:基于视图空间的法线和视线方向计算偏移,保证任何视角下都能正确识别边缘并生成合理偏移。

修正后的顶点着色器代码如下:

uniform mat4 modelViewMatrix;
uniform mat4 projectionMatrix;
varying vec3 normFrag;

void main() {
    // 将顶点转换到视图空间
    vec4 viewPos = modelViewMatrix * vertex;
    // 将法线转换到视图空间并归一化
    vec3 viewNormal = normalize(mat3(normalMatrix) * normal);
    
    // 计算视线方向(视图空间中相机在原点,视线方向为-viewPos的归一化结果)
    vec3 viewDir = normalize(-viewPos.xyz);
    
    // 通过法线与视线的点积判断边缘:边缘区域的点积值接近0
    float edgeFactor = 1.0 - abs(dot(viewNormal, viewDir));
    // 调整偏移幅度,可根据需求修改系数
    float offsetAmount = edgeFactor * 0.02;
    
    // 将法线投影到屏幕平面(去掉z分量),确保偏移方向为边缘垂直方向
    vec2 screenNormal = normalize(viewNormal.xy);
    // 视图空间内偏移顶点后,转换到裁剪空间
    vec4 offsetViewPos = viewPos + vec4(screenNormal * offsetAmount, 0.0, 0.0);
    gl_Position = projectionMatrix * offsetViewPos;
    
    // 传递法线给片元着色器(若后续片元阶段需要使用)
    normFrag = viewNormal;
}

关键改进点

  • 视图空间统一计算:所有法线、视线的计算都在视图空间完成,避免直接操作投影矩阵分量带来的兼容性问题,视角适应性更强。
  • 边缘因子控制偏移:通过法线与视线的点积精准识别边缘区域,只有边缘部分才会产生明显偏移,非边缘区域偏移量极小,不会影响主体模型。
  • 稳定的屏幕空间偏移:将法线投影到屏幕平面后再偏移,确保偏移方向始终是边缘的垂直方向,不会出现方向错误导致的边缘消失。

如果你想保留原有偏移思路,至少要修正投影矩阵分量的使用逻辑(比如基于透视矩阵的远裁剪面参数计算),但上面的方案会更通用可靠。

内容的提问来源于stack exchange,提问作者andre

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 07:00:45