绘制一个无限的地面平面

huangapple go评论61阅读模式
英文:

Drawing an infinite ground plane

问题

在旧版桌面GL中,要绘制一个无限延伸到近/远平面之外的地平面,您可以启用GL_DEPTH_CLAMP。

在WebGL中如何实现等效效果有什么提示?操纵gl_FragDepth并不太合适,因为裁剪会在片段着色之前发生。

我的使用情况是一个具有大型网格的建模应用程序,用户可以缩小视图而不希望看到网格被裁剪。我的相机的近/远平面相对较严格,以实现良好的深度精度和出色的SSAO效果。

英文:

To draw an infinite ground plane that extends beyond near / far planes, in old school desktop GL, you could enable GL_DEPTH_CLAMP.

Any tips for how to do the equivalent with WebGL? Manipulating gl_FragDepth isn't quite right because clipping occurs before fragment shading.

My use case is a modeling app with a large grid, and the user zooms out and doesn't want to see the grid clipped. My camera has fairly tight near / far planes to allow for good depth precision and nice SSAO.

答案1

得分: 0

无法使用网格显示真正的无限平面,因为您无法将无限坐标设置为平面的角落。

您可以使用光线跟踪技术。您的网格变成了一个覆盖整个屏幕的矩形,大部分工作都在片段着色器中完成。

简化一下,让我们想象您的无限平面在地面上,由这个简单的方程定义:z = 0。您需要找到无限平面与从摄像机位置抛出的射线的交点。

我写了一个示例,其中使用了具有90度视场的透视摄像机。如果视口是一个正方形,而摄像机处于静止状态,从摄像机中心经过屏幕右上角的射线与这个向量对齐:vec3(1.0, 1.0, 1.0)。由于其z坐标是正的(并且因为摄像机在平面上方),这意味着射线不会穿过平面。当然,右下角有一条射线相交,我们可以计算平面(x,y)坐标中的这个交点。

以下是顶点着色器:

#version 300 es

uniform mat3 uniCameraOrientation;
in vec2 attRay;
out vec3 varRay;

void main() {
    varRay = uniCameraOrientation * vec3(1.0, attRay);
    gl_Position = vec4(attRay, 0.0, 1.0);
}

以下是片段着色器:

#version 300 es

precision mediump float;

in vec3 varRay;
out vec4 FragColor;
const vec3 cameraPosition = vec3(0, 0, 1);

void main() {
    if (varRay.z >= 0.0) discard;

    float factor = -1.0 / varRay.z;
    float x = cameraPosition.x + factor * varRay.x;
    float y = cameraPosition.y + factor * varRay.y;
    float r = cos(x) * cos(y);
    FragColor = vec4(r > 0.0 ? vec3(0.2, .8, 0) : vec3(.3, .6, .1) , 1.0);
}

在此链接中查看其运行示例:https://codepen.io/tolokoban/full/WNaXBQb

英文:

Displaying a really infinite plan cannot be done with a mesh because you cannot set infinite coordinates to the corners of your plan.

What you could do is use a ray-tracing technique. Your mesh becomes a rectangle that covers the full screen and most of the job is done in the fragment shader.

To simplify let's imagine your infinite plan is on the ground, defined by this simple equation: z = 0. What you need is to find the intersection between your infinite plan and the ray that is thrown from the camera position.

I wrote an example with a perspective camera that has 90° of field of view. If the view port is a square and if the camera is at rest, the ray that goes from the camera center through the top right corner of the screen is align with this vector: vec3(1.0, 1.0, 1.0). Since its z coordinate is positive (and because the camera is above the plane) that means that the ray do not cross the plane. Of course, the bottom right corner has a ray intersecting and we can compute this intersection in the plane (x,y) coordinates.

Here is the vertex shader:

#version 300 es

uniform mat3 uniCameraOrientation;
in vec2 attRay;
out vec3 varRay;

void main() {
    varRay = uniCameraOrientation * vec3(1.0, attRay);
    gl_Position = vec4(attRay, 0.0, 1.0);
}

And here is the fragment shader:

#version 300 es

precision mediump float;

in vec3 varRay;
out vec4 FragColor;
const vec3 cameraPosition = vec3(0, 0, 1);

void main() {
    if (varRay.z >= 0.0) discard;

    float factor = -1.0 / varRay.z;
    float x = cameraPosition.x + factor * varRay.x;
    float y = cameraPosition.y + factor * varRay.y;
    float r = cos(x) * cos(y);
    FragColor = vec4(r > 0.0 ? vec3(0.2, .8, 0) : vec3(.3, .6, .1) , 1.0);
}

See it in action here: https://codepen.io/tolokoban/full/WNaXBQb

huangapple
  • 本文由 发表于 2023年4月7日 04:00:05
  • 转载请务必保留本文链接:https://go.coder-hub.com/75953324.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定