如果要渲染冒名顶质几何体(比如a sphere),那么标准做法是使用两个三角形绘制它(比如通过传递一个顶点并使用几何着色器制作三角形条)。 / p>
这很好,因为它可以相当简单地设置广告牌的范围:直接计算实际的世界空间位置。
几何着色器可以交替输出点基元,我看不出它们不应该的原因。唯一的问题是找到一些方法来扩展gl_PointSize
,以便你获得这种效果。
我能找到的唯一先例是this question(我的答案我不确定是正确的)和this question(没有答案)。
值得注意的是,用距离正确地缩放点是非常简单的(通过做gl_PointSize = constant/length(gl_Position)
,但这是不可控的;你不能说例如:我希望这一点看起来像是两个世界单位。
所以:有人知道怎么做吗?
答案 0 :(得分:13)
一个直接的想法是将粒子顶部和底部的一个点转换为屏幕空间并找到距离。这取消非常好,只使用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_clip
为gl_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;
}
片段:
#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);
}
(注意右下角的可见间隙不正确,如上所述)