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

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

问题描述

如果你想渲染一个冒名顶替的几何体(比如 2 3 4<小时>

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

顶点:

#version 150在 vec4 osVert 中;统一 mat4 投影垫;统一 mat4 modelviewMat;统一 vec2 vpSize;平坦的 vec2 中心;弄平浮动半径像素;const 浮点半径 = 1.0;无效主(){gl_Position = 投影垫 * 模型视图垫 * osVert;中心 = (0.5 * gl_Position.xy/gl_Position.w + 0.5) * vpSize;gl_PointSize = vpSize.y * projectionMat[1][5] * 半径/gl_Position.w;半径像素 = gl_PointSize/2.0;}

片段:

#version 150平坦在 vec2 中心;在浮动半径像素中平坦;出 vec4 fragColour;无效主(){vec2 coord = (gl_FragCoord.xy - center)/radiusPixels;浮动 l = 长度(坐标);如果 (l > 1.0)丢弃;vec3 pos = vec3(coord, sqrt(1.0-l*l));fragColour = vec4(vec3(pos.z), 1.0);}

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

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.

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).

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?

解决方案

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.

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.

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 ]

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...

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

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.


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]
Well, since I bothered to test this I'll throw my shaders here too...

Vertex:

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

Fragment:

#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天全站免登陆