gl_PointSize对应世界空间大小

ima*_*ett 11 opengl glsl

如果要渲染冒名顶质几何体(比如球体),则标准练习是使用两个三角形绘制它(例如,通过传递一个顶点并使用几何着色器制作三角形条带).

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

几何着色器可以交替输出点基元,我没有看到它们不应该的原因.唯一的问题是找到一些扩展方法,gl_PointSize以便你获得这种效果.

我能找到的唯一先例是这个问题(我的答案我不确定是正确的)和这个问题(没有答案).

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

那么:谁知道怎么做?

joz*_*yqk 14

一个直截了当的想法是将粒子顶部和底部的点转换为屏幕空间并找到距离.这取消非常好,并且只使用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 ]
Run Code Online (Sandbox Code Playgroud)

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透视矩阵中).为了保证您的点覆盖您想要的每个像素,这可能需要一个额外的小常量.


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


[ 编辑 ]
嗯,因为我打扰测试这个我也会把我的着色器扔到这里...

顶点:

#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;
}
Run Code Online (Sandbox Code Playgroud)

分段:

#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);
}
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

(注意右下方的可见间隙不正确,如上所述)

  • 在webgl中我使用了projectionMat[1][1]而不是projectionMat[1][5] (2认同)