OpenGL中如何计算平行于立方体表面的网格裁剪平面?
OpenGL轴对齐裁剪平面计算方法
核心原理
三维裁剪平面的通用表达式为 Ax + By + Cz + D = 0,对应GLSL中使用的vec4格式平面参数为vec4(A, B, C, D)。将待检测的点坐标扩展为齐次坐标vec4(pos, 1.0)后,和平面参数做点积得到的结果为带符号距离值:
- 结果大于0:点位于平面法向量
(A,B,C)指向的一侧,属于保留区域 - 结果小于0:点位于平面另一侧,属于裁剪丢弃区域
- 结果等于0:点恰好落在平面上
你现有代码的核心问题是对gl_Position(裁剪空间坐标)计算点积,该空间坐标经过投影变换,无法直接和立方体的实际顶点位置对齐,计算出的裁剪平面位置会随相机参数、透视效果偏移。正确做法是在本地坐标空间或世界坐标空间计算裁剪距离,不要经过视图、投影变换。
平行于立方体面的平面参数计算
常规立方体为轴对齐结构,6个面分别垂直于X、Y、Z三个坐标轴,平行于对应面的裁剪平面法向量仅单个分量非零,参数计算逻辑完全统一,以下以本地坐标下中心在原点、坐标范围为[-1,1]的立方体为例,其他尺寸/位置的立方体只需替换对应阈值坐标即可:
- 平行于YZ平面(垂直X轴,裁剪左右方向)
- 保留所有x坐标大于x0的区域:平面参数为
vec4(1.0, 0.0, 0.0, -x0) - 保留所有x坐标小于x0的区域:平面参数为
vec4(-1.0, 0.0, 0.0, x0) - 示例:从立方体中心x=0位置裁剪,丢弃左半部分保留右半,平面参数为
vec4(1.0, 0.0, 0.0, 0.0)
- 保留所有x坐标大于x0的区域:平面参数为
- 平行于XZ平面(垂直Y轴,裁剪上下方向)
- 保留所有y坐标大于y0的区域:平面参数为
vec4(0.0, 1.0, 0.0, -y0) - 保留所有y坐标小于y0的区域:平面参数为
vec4(0.0, -1.0, 0.0, y0) - 示例:从立方体中心y=0位置裁剪,丢弃下半部分保留上半,平面参数为
vec4(0.0, 1.0, 0.0, 0.0)
- 保留所有y坐标大于y0的区域:平面参数为
- 平行于XY平面(垂直Z轴,裁剪前后方向)
- 保留所有z坐标大于z0的区域:平面参数为
vec4(0.0, 0.0, 1.0, -z0) - 保留所有z坐标小于z0的区域:平面参数为
vec4(0.0, 0.0, -1.0, z0) - 示例:从立方体中心z=0位置裁剪,丢弃后一半保留前半,平面参数为
vec4(0.0, 0.0, 1.0, 0.0)
- 保留所有z坐标大于z0的区域:平面参数为
注意:如果你的立方体本地坐标范围不是[-1,1],例如是[0,1]范围、中心在(0.5,0.5,0.5)的立方体,要从中心对半裁剪,只需要把对应轴的阈值设为0.5即可,比如裁剪x<0.5的部分,平面参数为
vec4(1.0,0.0,0.0,-0.5),直接用顶点本地坐标aPos计算点积即可。如果平面定义在世界空间,就用模型矩阵变换后的世界坐标计算点积。
修正后的代码参考
片元着色器(原有逻辑无需修改)
#version 120 varying vec3 ourColor; varying float clip_distance; void main() { if ( clip_distance < 0.0 ) discard; gl_FragColor = vec4(ourColor, 1.0); }
顶点着色器(修正裁剪距离计算逻辑)
#version 120 attribute vec3 aPos; attribute vec3 aColor; varying vec3 ourColor; uniform mat4 model; uniform mat4 view; uniform mat4 projection; varying float clip_distance; // 示例:平行于YZ平面,从中心裁剪保留x>0的右半部分,平面定义在世界空间 const vec4 clipPlane = vec4(1.0, 0.0, 0.0, 0.0); void main() { vec4 worldPos = model * vec4(aPos, 1.0); gl_Position = projection * view * worldPos; // 使用世界坐标计算裁剪距离,不要使用gl_Position clip_distance = dot(worldPos, clipPlane); ourColor = aColor; }
内容的提问来源于stack exchange,提问作者Андрей Петров
相关产品推荐
相关产品推荐

