gl_PointSize 对应世界空间大小

Posted

技术标签:

【中文标题】gl_PointSize 对应世界空间大小【英文标题】:gl_PointSize Corresponding to World Space Size 【发布时间】:2014-09-11 06:02:59 【问题描述】:

如果你想渲染一个冒名顶替的几何体(比如a sphere),那么标准做法是使用两个三角形来绘制它(比如通过一个顶点并使用几何着色器制作一个三角形条带)。

这很好,因为它允许相当简单地设置广告牌的范围:您可以直接计算实际的世界空间位置。

几何着色器可以交替输出点图元,我看不出他们不应该这样做的原因。唯一的问题是找到某种方法来扩展 gl_PointSize 以便获得这种效果。

我能找到的唯一先例是this question(我不确定其答案是否正确)和this question(没有答案)。

值得注意的是,用距离正确缩放点相当简单(通过gl_PointSize = constant/length(gl_Position),但这不是可控的;你不能说例如:我希望这个点看起来像两个世界单位。

那么:有人知道怎么做吗?

【问题讨论】:

【参考方案1】:

一个直截了当的想法是将粒子顶部和底部的一个点转换到屏幕空间并找到距离。这可以很好地取消,并且仅使用 y 坐标非常简单。

广告牌是屏幕对齐的,并且视图矩阵通常不会缩放,因此世界空间中的粒子大小与眼睛空间相同。这只是将投影留给 NDC,除以 w 并按视口大小缩放。

一个典型的投影矩阵,P,可能看起来像这样......

[ +1.2990 +0.0000 +0.0000 +0.0000 ]
[ +0.0000 +1.7321 +0.0000 +0.0000 ]
[ +0.0000 +0.0000 -1.0002 -0.0020 ]
[ +0.0000 +0.0000 -1.0000 +0.0000 ]

y_eye开头,眼睛空间中的一个y坐标,得到图像空间坐标y_image,以像素为单位……

插入广告牌上方/下方的半径并减去取消以...

或者,在文本中,pixelSize = vpHeight * P[1][1] * radius / w_clip

对于透视投影,P[1][1] = 1 / tan(fov_y / 2)w_clipgl_Position.w,也是-z_eye(来自透视矩阵中的-1)。为确保您的点涵盖您想要的每个像素,这可能需要一个额外的小常数。


旁注:广告牌上的球体在屏幕中间看起来不错。如果您有大视野透视投影,则真正的球体在接近屏幕边缘时应该会变形。您可以为广告牌中的每个像素隐式投射虚拟球体以获得正确的结果,但广告牌边界需要相应调整。谷歌快速搜索结果:1234


[编辑] 好吧,既然我费心测试这个,我也会把我的着色器扔在这里......

顶点:

#version 150

in vec4 osVert;

uniform mat4 projectionMat;
uniform mat4 modelviewMat;
uniform vec2 vpSize;

flat out vec2 centre;
flat out float radiusPixels;

const float radius = 1.0;

void main()

    gl_Position = projectionMat * modelviewMat * osVert;
    centre = (0.5 * gl_Position.xy/gl_Position.w + 0.5) * vpSize;
    gl_PointSize = vpSize.y * projectionMat[1][5] * radius / gl_Position.w;
    radiusPixels = gl_PointSize / 2.0;

片段:

#version 150

flat in vec2 centre;
flat in float radiusPixels;

out vec4 fragColour;

void main()

    vec2 coord = (gl_FragCoord.xy - centre) / radiusPixels;
    float l = length(coord);
    if (l > 1.0)
        discard;
    vec3 pos = vec3(coord, sqrt(1.0-l*l));
    fragColour = vec4(vec3(pos.z), 1.0);

(请注意右下角的可见间隙如上所述是不正确的)

【讨论】:

+1;感谢您的深入回答。但是,我无法得到正确的结果;我想你的意思是cot(fov_y/2)?在这种情况下,我的测试表明该点太大了 2.0 倍。 @IanMallett 在所有帐户上都是正确的!道歉。更新。我忘记考虑 NDC 大小是 2(-1 到 1),稍后会取消。 在 webgl 中我使用了 projectionMat[1][1] 而不是 projectionMat[1][5] 这个答案和@Inuart 的评论都为我节省了很多时间。它确实有效!谢谢!

以上是关于gl_PointSize 对应世界空间大小的主要内容,如果未能解决你的问题,请参考以下文章

从 GL_POINT 到相机的距离确定 gl_PointSize

解决 three.js / webGL 中的 gl_PointSize 限制

U3D屏幕坐标,世界坐标,像素坐标之间的关系

使用 gl_PointSize 来扩大和缩小点

存储世界空间坐标

Unity Shaderlab-从屏幕空间到世界空间的转换