我如何计算给定物体的表面点?

问题描述 投票:0回答:1

我正在 GLSL 中实现光线行进,以通过表面点可视化渲染球形对象。从某些角度查看物体时会出现此问题 - 表面位置计算变得不正确。

这是我的片段着色器:

#version 400

out vec4 FragColor;
in vec3 color;
in vec3 Normal;
in vec3 CurrentPos;

uniform int sunCount;
uniform int planetCount;
uniform vec4 lightColor;
uniform vec3 lightPos[64];
uniform vec3 viewPos;
uniform mat4 projectionMatrix;
uniform mat4 viewMatrix;
uniform vec3 sphereOrigin[64];
uniform float sphereRadius[64];

// SDF for spheres
float SDF(in vec3 p, in vec3 c, float r) {
    return length(p - c) - r;
}

vec3 calculateSurfacePos() {
    // Get normalized device coordinates (NDC) from gl_FragCoord
    vec2 uv_nds = (gl_FragCoord.xy / vec2(1366.0, 768.0)) * 2.0 - 1.0;
    
    vec4 uv_clip = vec4(uv_nds, -1.0, 1.0);
    vec4 uv_eye = inverse(projectionMatrix) * uv_clip;
    uv_eye = vec4(uv_eye.x, uv_eye.y, -1.0, 0.0);
    vec3 uv_wor = (inverse(viewMatrix) * uv_eye).xyz;
    uv_wor = normalize(uv_wor);

    highp float t = 0.0;
    highp vec3 ro = viewPos;
    highp vec3 rd = uv_wor;

    for (int i = 0; i < 256; i++) {
        highp vec3 p = ro + rd * t;
        float dist = 1e10;

        for (int j = 0; j < planetCount; j++) {
            dist = min(dist, SDF(p, sphereOrigin[j], sphereRadius[j]));
        }

        if (dist < 0.001) return p;
        if (t > 100.) break;

        t += dist;
    }
    return vec3(0.0);
}

void main() {
    vec3 surfacePos = calculateSurfacePos();
    FragColor = vec4(surfacePos, 1.0);
}

将其作为输出: enter image description here

我希望球体在我面对它时被填充,而不是在某些角度 enter image description here

我尝试过的:

使用 SDF 方法实现射线行进来查找与多个球体的交点。 正确地将设备坐标标准化为世界坐标。 使用循环沿着射线行进,直到找到交叉点或达到限制。 如果找到则返回交点,否则返回默认值。

当前问题:

计算的表面位置 (surfacePos) 未提供与球体的预期交点。相反,我得到了意想不到的颜色或根本没有交叉点。 我不确定我计算射线方向和行进逻辑的方法是否正确。

问题:

从剪辑空间转换到眼睛空间再到世界空间时,我的转换逻辑是否有错误? 我应该考虑光线行进的任何优化或最佳实践吗? 如何更有效地调试交叉点以确保我的 SDF 返回正确的距离?

glsl fragment-shader raymarching
1个回答
0
投票

所以我这样做的方式是将所有行星位置的列表发送到片段着色器,但我需要单独发送它们以及所有行星的列表,为什么?很简单,因为对于每个行星,我们需要检查它们的光线方向内是否有相交,所以最终我的理论是检查光线与 UV 坐标相交的位置,但后来我发现这是因为计算 t += dist看起来很容易受到浮点误差的影响。

vec3 computeShadow(in vec3 lightPos) {
    float t = 0.0;
    vec3 ro = lightPos;
    vec3 rd = normalize(sphereOrigin - lightPos);

    float maxDistToSphere = length(lightPos - sphereOrigin) - sphereRadius;

    for (int i = 0; i < 100 && t < maxDistToSphere; i++) {
        vec3 p = ro + t * rd; // Position along the ray
        float minDist = 1e9;

        // Check to each sphere (planet)
        for (int k = 0; k < planetCount; k++) {
            vec3 toPlanet = normalize(spheresOrigin[k] - lightPos); 

            // Check if the planet is roughly in the ray direction
            if (dot(rd, toPlanet) > 0.99) { // Allowing a slight tolerance
                float dist = SDF(p, spheresOrigin[k], spheresRadius[k]);
                minDist = min(minDist, dist);
            }
        }

        // If the ray is close enough to a surface, consider it in shadow
        if (minDist < 0.01) return vec3(t / float(80) * 4.0); // Soft shadow effect
        
        t += minDist; // Step forward along the ray
    }
    
    // If no shadow encountered, return light
    return vec3(1.0);
}

maxDistToSphere 是太阳与球体中行星点之间的长度 在 if 条件下

if (dot(rd, toPlanet) > 0.99)
我们检查这些行星的方向,如果它们与我们当前正在检查的行星对齐,它们是否完全对齐,我们计算它们的距离,如果 t 达到高于 maxDistToSphere 的距离,则返回软阴影,因此没有行星处于同一方向

© www.soinside.com 2019 - 2024. All rights reserved.