【问题标题】:How do I align the raytraced spheres from my fragment shader with GL_POINTS?如何将片段着色器中的光线追踪球体与 GL_POINTS 对齐?
【发布时间】:2022-11-11 22:30:36
【问题描述】:

我有一个非常简单的着色器程序,它将一堆位置数据作为 GL_POINTS 生成屏幕对齐的片段正方形,就像正常的大小取决于深度一样,然后在片段着色器中我想绘制一个非常简单的光线追踪每个球体,只有与光相对的球体上的阴影。我去了shadertoy 试图自己解决这个问题。我使用 sphIntersect 函数进行光线-球体相交,并使用 sphNormal 来获取球体上的法线向量以进行照明。问题是球体不与碎片的正方形对齐,导致它们被切断。这是因为我不确定如何匹配球体的投影和顶点位置以使它们对齐。我可以解释一下如何做到这一点吗?

这是一张供参考的图片。

这是我的顶点和片段着色器供参考:

//vertex shader:
#version 460

layout(location = 0) in vec4 position; // position of each point in space
layout(location = 1) in vec4 color; //color of each point in space
layout(location = 2) uniform mat4 view_matrix; // projection * camera matrix
layout(location = 6) uniform mat4 cam_matrix; //just the camera matrix
out vec4 col; // color of vertex
out vec4 posi; // position of vertex

void main() {
    vec4 p = view_matrix * vec4(position.xyz, 1.0);
    gl_PointSize = clamp(1024.0 * position.w / p.z, 0.0, 4000.0);
    gl_Position = p;
    col = color;
    posi = cam_matrix * position;
}

//fragment shader:
#version 460

in vec4 col; // color of vertex associated with this fragment
in vec4 posi; // position of the vertex associated with this fragment relative to camera

out vec4 f_color;

layout (depth_less) out float gl_FragDepth;

float sphIntersect( in vec3 ro, in vec3 rd, in vec4 sph )
{
    vec3 oc = ro - sph.xyz;
    float b = dot( oc, rd );
    float c = dot( oc, oc ) - sph.w*sph.w;
    float h = b*b - c;
    if( h<0.0 ) return -1.0;
    return -b - sqrt( h );
}

vec3 sphNormal( in vec3 pos, in vec4 sph )
{
    return normalize(pos-sph.xyz);
}

void main() {

    vec4 c = clamp(col, 0.0, 1.0);
    vec2 p = ((2.0*gl_FragCoord.xy)-vec2(1920.0, 1080.0)) / 2.0;
    
    vec3 ro = vec3(0.0, 0.0, -960.0 );
    vec3 rd = normalize(vec3(p.x, p.y,960.0));
    
    vec3 lig = normalize(vec3(0.6,0.3,0.1));

    vec4 k = vec4(posi.x, posi.y, -posi.z, 2.0*posi.w);

    float t = sphIntersect(ro, rd, k);
    vec3 ps = ro + (t * rd);
    vec3 nor = sphNormal(ps, k);
    
    if(t < 0.0) c = vec4(1.0);
    
    else c.xyz *= clamp(dot(nor,lig), 0.0, 1.0);

    f_color = c;

    gl_FragDepth = t * 0.0001;

}

【问题讨论】:

标签: opengl glsl raytracing


【解决方案1】:

看起来你有很多领域,所以我会这样做:

  1. 输入数据

    我会让 VBO 包含 x,y,z,r 描述你的球体,你还需要你的视图变换(统一),它可以为每个片段创建光线方向和起始位置。像我的顶点着色器在这里:

  2. 在几何着色器中创建 BBOX 并将您的 POINT 转换为 QUAD 或 POLYGON

    请注意,您必须考虑视角。如果您不熟悉几何着色器,请参阅:

    我从输入线发出 OBB 序列的地方......

  3. 在片段光线追踪球体中

    您必须计算intersection between sphere and ray,选择较近的交叉点并计算其深度和法线(用于照明)。如果没有路口,您必须discard;片段!

    从我在您的图像中看到的内容来看,您的 QUAD 与您的球体不对应,因此进行了裁剪,而且您也没有 discard; 没有交叉点的片段,因此您使用背景颜色覆盖已在最后渲染的球体周围渲染的东西,因此您只有一个球体无论有多少球体,都留在QUAD中......

【讨论】:

  • 我已经有了 x, y, z, r 的位置,因此为什么它是 vec4,当我查看变换时我省略了 w。另外,我没有在 gif 中丢弃的原因是为了清楚地指出正方形的边界在哪里,否则因为投影不对齐球体是不可见的,我会盲目地移动相机以找到他们。还有,做BBOX真的有必要吗?与使正方形更大以使球体在离开屏幕之前不会剪辑,这会对性能产生多大影响?老实说,我只是想让预测排列起来。
  • 那么我想真正的问题是:如果我有一个投影矩阵和半径,我怎么能... 1)创建正确大小的 bbox?以及 2) 定义与投影矩阵创建相同投影的光线?
  • @PlatinumFrog 和 MVP 很棘手...最好单独访问 VIEW 和 MESH 矩阵,因为您需要提取相机轴以创建有效的 BBOX ...所以您只需在网格本地创建正方形(或任何东西)在与相机投影平面平行的平面中围绕球心坐标...这在几何着色器中很容易完成...您可以使用您的 MVP 进行转换...这几乎没有性能影响...真正的影响可以只能在旧硬件上使用几何着色器(而不是其中的代码),但是现代 GL 驱动程序和 gfx 卡应该没问题。
【解决方案2】:

要从屏幕空间创建与透视矩阵匹配的光线方向,可以使用以下光线方向公式:

vec3 rd = normalize(vec3(((2.0 / screenWidth) * gl_FragCoord.xy) - vec2(aspectRatio, 1.0), -proj_matrix[1][1]));

2.0 / screenWidth 的值可以预先计算,也可以使用 opengl 内置的统一结构。

要获得球体的边界框或其他形状,使用面向相机的形状非常重要,而不是面向相机平面的形状。使用以下过程,其中position 是传入的 VBO 位置数据,position 的 w 分量是半径:

vec4 p = vec4((cam_matrix * vec4(position.xyz, 1.0)).xyz, position.w);
o.vpos = p;

float l2 = dot(p.xyz, p.xyz);
float r2 = p.w * p.w;
float k = 1.0 - (r2/l2);
float radius = p.w * sqrt(k);
if(l2 < r2) {
    p = vec4(0.0, 0.0, -p.w * 0.49, p.w);
    radius = p.w;
    k = 0.0;
}
vec3 hx = radius * normalize(vec3(-p.z, 0.0, p.x));
vec3 hy = radius * normalize(vec3(-p.x * p.y, p.z * p.z + p.x * p.x, -p.z * p.y));
p.xyz *= k;

然后使用hxhy 作为任何二维形状的基向量,您希望广告牌的形状与顶点的形状类似。稍后不要忘记将每个顶点乘以透视矩阵以获得每个顶点的最终位置。这是使用六边形在desmos上的广告牌的可视化:https://www.desmos.com/calculator/yeeew6tqwx

【讨论】:

    猜你喜欢
    • 2017-07-12
    • 1970-01-01
    • 1970-01-01
    • 2017-03-26
    • 2019-11-29
    • 2018-11-19
    • 2019-11-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多