【问题标题】:world position to screen position in fragment shader glsl片段着色器 glsl 中屏幕位置的世界位置
【发布时间】:2026-01-11 22:15:01
【问题描述】:

我有一个 WebGL 渲染器,我想将随机世界坐标转换为片段着色器中的屏幕坐标。

这将允许我将“计算的屏幕坐标”与当前片段屏幕坐标进行比较。

我相信我拥有这样做所需的所有信息,只是不确定哪种方法是正确的。

  ...
  // available information:

  // uCanvasWidth (float)
  // uCanvasHeight (float)
  // modelMatrix (mat4)
  // modelViewMatrix (mat4)
  // projectionMatrix (mat4)
  vec4 someWorldCoordinates = vec4(1., 2., 3., 1.);
  // map it to screen coordinates?
  vec4 screenCoordinates = ???

  // compare to current fragment location
  if(screenCoordinates.x > gl_FragCoord.x){
    // do stuff
  }
  ...

【问题讨论】:

    标签: glsl webgl fragment-shader coordinate-transformation


    【解决方案1】:
    vec4 worldSpace = vec4(1., 2., 3., 1.);
    // get homogeneous clip space coordinates
    vec4 clipSpace = projectionMatrix * ( modelViewMatrix * worldCoords );
    // apply perspective divide to get normalized device coordinates
    vec3 ndc = clipSpace.xyz / clipSpace.w;
    // do viewport transform
    vec2 screenSpace = (ndc.xy * .5 + .5) * vec2(uCanvasWidth, uCanvasHeight);
    screenSpace.y = uCanvasHeight - screenSpace.y;
    

    请注意,您的modelView 矩阵可能包含您正在渲染的模型的变换。我会假设着色器中指定的点被认为已经是“final”世界空间(与您正在渲染的模型无关),因此您可能只想使用 @这里是987654323@矩阵(最好是预乘的viewProjection)。

    【讨论】:

    • 我想这会给你一个倒置的screenSpace.y
    • 应该是screenSpace = (ndx.xy * .5 + .5) * vec2(viewportWidth, viewportIHeight) + vec2(viewportLeft, viewportRight);
    • @gman 是的,这可能是正确的并且是更通用的解决方案,但在我的情况下,我的视口与我的画布大小相同!
    • @gman 是的,完整的视口转换是这样的(假设您的意思是+vec2(viewportLeft, viewportTop)