在 GLSL 着色器中计算点投影
Calculate point projection in GLSL shader
我需要在着色器 (OpenGL ES 2) 中计算点在特定线段上的投影。
以下是我如何测试算法:
我用点 A(0, 0.5)、B(1, -0.5)、C(-1, -0.5) 绘制简单的三角形。
我计算线段 AC 上每个点的投影。
我用蓝色线段 AC 中间的投影绘制点。其余点为绿色。
我希望得到一个绿色三角形和一条垂直于 AC 边的蓝线。但是蓝线不垂直于AC。
我检查代码中的投影公式并在 canvas 上绘图并得到预期结果。
我的错误是什么?
着色器结果:
顶点着色器:
uniform mat4 matrix;
attribute vec4 position;
varying vec4 vPosition;
void main()
{
vPosition = matrix * position;
gl_Position = matrix * position;
}
片段着色器:
precision mediump float;
varying vec4 vPosition;
void main()
{
vec2 P = vPosition.xy;
vec2 A = vec2(0.0, 0.5);
vec2 B = vec2(-1.0, -0.5);
vec2 AP = P - A;
vec2 AB = B - A;
vec2 projection = A + dot(AP, AB) / dot(AB, AB) * AB;
if(projection.x > -0.51 && projection.x < -0.49 && projection.y > -0.01 && projection.y < 0.01) {
gl_FragColor = vec4(0.0, 0.0, 1.0, 1.0);
} else {
gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);
}
}
您没有考虑 window 的矩形方面。当 [-1, 1] 范围内的规范化设备坐标映射到视口矩形(参见 glViewport
)时,三角形会被拉伸。这导致无法保持 90 度角。
向包含视口宽度和高度的片段着色器添加一个uniform variable:
uniform vec2 u_resolution;
计算纵横比:
float aspect = u_resolution.x / u_resolution.y;
当然你也可以用一个常数值初始化变量float aspect
。
例如float aspect = 16.0/9.0;
根据纵横比修正点A
、B
、P
的坐标:
vec2 P = vPosition.xy;
vec2 A = vec2(0.0, 0.5);
vec2 B = vec2(-1.0, -0.5);
A.x *= aspect;
B.x *= aspect;
P.x *= aspect;
并在评估结果时考虑纵横比projection
:
vec2 projection = A + dot(AP, AB) / dot(AB, AB) * AB;
projection.x /= aspect;
最终片段着色器可能如下所示:
precision mediump float;
varying vec4 vPosition;
uniform vec2 u_resolution;
void main()
{
float aspect = u_resolution.x / u_resolution.y;
vec2 as = vec2(aspect, 1.0);
vec2 P = as * vPosition.xy;
vec2 A = as * vec2(0.0, 0.5);
vec2 B = as * vec2(-1.0, -0.5);
vec2 AP = P - A;
vec2 AB = B - A;
vec2 projection = A + dot(AP, AB) / dot(AB, AB) * AB / as;
if(projection.x > -0.51 && projection.x < -0.49 && projection.y > -0.01 && projection.y < 0.01) {
gl_FragColor = vec4(0.0, 0.0, 1.0, 1.0);
} else {
gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);
}
}
我需要在着色器 (OpenGL ES 2) 中计算点在特定线段上的投影。
以下是我如何测试算法:
我用点 A(0, 0.5)、B(1, -0.5)、C(-1, -0.5) 绘制简单的三角形。
我计算线段 AC 上每个点的投影。
我用蓝色线段 AC 中间的投影绘制点。其余点为绿色。
我希望得到一个绿色三角形和一条垂直于 AC 边的蓝线。但是蓝线不垂直于AC。
我检查代码中的投影公式并在 canvas 上绘图并得到预期结果。
我的错误是什么?
着色器结果:
顶点着色器:
uniform mat4 matrix;
attribute vec4 position;
varying vec4 vPosition;
void main()
{
vPosition = matrix * position;
gl_Position = matrix * position;
}
片段着色器:
precision mediump float;
varying vec4 vPosition;
void main()
{
vec2 P = vPosition.xy;
vec2 A = vec2(0.0, 0.5);
vec2 B = vec2(-1.0, -0.5);
vec2 AP = P - A;
vec2 AB = B - A;
vec2 projection = A + dot(AP, AB) / dot(AB, AB) * AB;
if(projection.x > -0.51 && projection.x < -0.49 && projection.y > -0.01 && projection.y < 0.01) {
gl_FragColor = vec4(0.0, 0.0, 1.0, 1.0);
} else {
gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);
}
}
您没有考虑 window 的矩形方面。当 [-1, 1] 范围内的规范化设备坐标映射到视口矩形(参见 glViewport
)时,三角形会被拉伸。这导致无法保持 90 度角。
向包含视口宽度和高度的片段着色器添加一个uniform variable:
uniform vec2 u_resolution;
计算纵横比:
float aspect = u_resolution.x / u_resolution.y;
当然你也可以用一个常数值初始化变量float aspect
。
例如float aspect = 16.0/9.0;
根据纵横比修正点A
、B
、P
的坐标:
vec2 P = vPosition.xy;
vec2 A = vec2(0.0, 0.5);
vec2 B = vec2(-1.0, -0.5);
A.x *= aspect;
B.x *= aspect;
P.x *= aspect;
并在评估结果时考虑纵横比projection
:
vec2 projection = A + dot(AP, AB) / dot(AB, AB) * AB;
projection.x /= aspect;
最终片段着色器可能如下所示:
precision mediump float;
varying vec4 vPosition;
uniform vec2 u_resolution;
void main()
{
float aspect = u_resolution.x / u_resolution.y;
vec2 as = vec2(aspect, 1.0);
vec2 P = as * vPosition.xy;
vec2 A = as * vec2(0.0, 0.5);
vec2 B = as * vec2(-1.0, -0.5);
vec2 AP = P - A;
vec2 AB = B - A;
vec2 projection = A + dot(AP, AB) / dot(AB, AB) * AB / as;
if(projection.x > -0.51 && projection.x < -0.49 && projection.y > -0.01 && projection.y < 0.01) {
gl_FragColor = vec4(0.0, 0.0, 1.0, 1.0);
} else {
gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);
}
}