gl_PointSize对应于世界空间大小 [英] gl_PointSize Corresponding to World Space Size

查看:184
本文介绍了gl_PointSize对应于世界空间大小的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如果您要渲染冒名顶替的几何形状(例如球体),那么标准做法是使用两个三角形绘制(例如,通过一个顶点并用几何着色器制作一个三角形条).

If you want to render an imposter geometry (say like a sphere), then the standard practice is to draw it using two triangles (say by passing one vertex and making a triangle strip with a geometry shader).

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

This is nice because it allows the extent of the billboard to be set fairly simply: you compute the actual world space positions directly.

几何着色器可以交替输出点图元,我不知道为什么不应该这样做.唯一的问题是找到一种缩放gl_PointSize的方法,以便获得那种效果.

Geometry shaders can alternately output point primitives, and I don't see a reason why they shouldn't. The only issue is finding some way to scale gl_PointSize so that you get that effect.

我唯一能找到的先例是这个问题(我不确定谁的答案是正确的),并此问题 (未答复).

The only precedent I could find were this question (whose answer I am unsure is correct) and this question (which is unanswered).

值得注意的是,通过距离正确缩放点非常简单(通过执行gl_PointSize = constant/length(gl_Position),但这是不可控制的;例如,您不能说:我希望此点看起来像是两个世界整个单位.

It's worth noting that it's fairly simple to scale the point correctly with distance (by doing gl_PointSize = constant/length(gl_Position), but this isn't controllable; you can't say for example: I want this point to look like it is two world units across.

所以:有人知道怎么做吗?

So: anyone know how to do this?

推荐答案

直截了当的想法是将粒子顶部和底部的点转换为屏幕空间并找到距离.取消效果非常好,仅使用y坐标即可非常简单.

A straight forward idea is to transform a point at the top and bottom of the particle into screen space and find the distance. This cancels very nicely and it's pretty simple to work with just the y coordinate.

广告牌是屏幕对齐的,并且视图矩阵通常不会缩放,因此世界空间中的粒子大小与眼睛空间相同.剩下的只是投影到达NDC,除以w并按视口大小进行缩放.

The billboard is screen aligned, and view matrices generally don't scale, so the particle size in world space is the same as eye space. That just leaves the projection to get to NDC, the divide by w and scaling by the viewport size.

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

A typical projection matrix, P, might look something like this...

[ +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以像素为单位...

Starting with y_eye, a y coordinate in eye space, the image space coordinate y_image is obtained in pixels...

在广告牌上方/下方插入半径,然后减去以抵消...

Plugging in the radius above/below the billboard and subtracting cancels to...

或者以文本形式, pixelSize = vpHeight * P[1][1] * radius / w_clip

Or, in text, pixelSize = vpHeight * P[1][1] * radius / w_clip

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

For a perspective projection, P[1][1] = 1 / tan(fov_y / 2). w_clip is gl_Position.w, which is also -z_eye (from the -1 in the perspective matrix). To guarantee your point covers every pixel you want, this may need an additional small constant.

侧面说明:广告牌上的球体在屏幕中间看起来不错.如果您有较大的视野透视投影,则真实的球体应在接近屏幕边缘时弯曲.您可以隐式地对广告牌中的每个像素进行虚拟球体透视,以获取正确的结果,但是广告牌边界需要相应地进行调整.谷歌快速搜索结果: 1 4

Side note: A sphere on a billboard will look OK in the middle of the screen. If you have a large field of view perspective projection, a true sphere should warp as it approaches the edges of the screen. You could implicitly raycast the virtual sphere for each pixel in the billboard to get a correct result, but the billboard boundary will need to be adjusted accordingly. Quick google results: 1 2 3 4

[ EDIT ]
好吧,由于我不愿意对此进行测试,所以我也将着色器也放在这里...

[EDIT]
Well, since I bothered to test this I'll throw my shaders here too...

顶点:

#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);
}

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

(Note the visible gap at the bottom right is incorrect as described above)

这篇关于gl_PointSize对应于世界空间大小的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆