首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >段上最近的球面

段上最近的球面
EN

Computer Graphics用户
提问于 2020-06-11 10:11:07
回答 1查看 74关注 0票数 0

我试图在曲面上得到一个段最近的点,并在这个位置上显示一个圆(在这种情况下是球体)。

实际上,我得到了正确的位置,但是我不能根据计算的数据得到一个均匀的球。

下面是我用来找到交点和绘制球体的相关代码。

代码语言:javascript
运行
复制
float3 a = from;
float3 b = to;
float3 c = worldPosition;

float3  ab = b - a;
float t = dot(c - a, ab) / dot(ab, ab);
float3 point = a + saturate(t) * ab;

return length(point - worldPosition) - radius;
EN

回答 1

Computer Graphics用户

发布于 2020-06-11 11:52:32

你的实际结果是正确的,因为你可以在一个片段着色器一次通过。它计算碎片的世界位置到线段的距离。每个片段的距离是不同的,所以拉伸的黑色椭球是正确的输出。

片段着色器只有正在处理的当前片段的本地信息。你不能再用那个做更多了。您的预期结果需要一些关于场景的全局知识,因为您正在搜索整个表面的最小距离。

在不考虑优化问题的情况下,朴素解路径应该包含片段到线距离的局部极小值的上下文计算。为了得到这样的上下文,您需要先计算距离字段,然后访问它,以便在单独的pass中找到局部最小值。

  1. 在第一遍中计算原始距离字段(与您的示例相同,但最后没有radius减法)。
  2. 在第二次传递中用局部极小值标记像素(例如,将alpha通道设置为1)。这将是屏幕空间通行证。最好是在输出时有一个rgba浮点纹理,rgb是片段的世界位置,a是局部极小值和0的位置。
  3. 在第三遍画黑圈/球体(也是屏幕空间)。

有了关于距离函数的局部最小值的信息,您就可以在最后一次输出最小值附近的正确形状。伪码:

代码语言:javascript
运行
复制
vec4 worldPos = tex2D(distance_texture, frag.x, frag.y);
if (worldPos.a > 0.5) //is minimum
    return vec3(0,0,0);
else
{
    //Sample the screen-space neighborhood in larger and larger circles
    // until a fragment with distance.a == 1 is found
    // or until all fragments are more than radius away (in world coords).

    //Minimum world space distance of any sampled fragment.
    float minDist = 0.0;
    int iter = 1;
    //Search for a local minimum until all fragments are more than radius away,
    // since then even if a local minimum gets found it will no longer produce
    // the black shading.
    while (minDist < radius && minDist >= 0.0 && iter < Math.Max(screenWidth, screenHeight))
        minDist = sampleNeighborhood(iter++, worldPos);

    if (minDist < 0.0) //found a local minimum
        return vec3(0,0,0);
    else
        return vec3(1,1,1); //or any other computed shading

    //I am aware that the function call above checks central fragments several times.
    //That should be of course optimized in production code.
}

float sampleNeighborhood(int neigh, vec4 worldPos)
{
    float minDist = float.MaxValue;
    for(int x = Math.max(0, frag.x - neigh); x <= Math.Min(screenWidth, frag.x + neigh; ++x)
        for(int y = Math.max(0, frag.y - neigh); x <= Math.Min(screenHeight, frag.y + neigh; ++y)
        {
            float p = tex2D(distance_texture, x, y);
            float d = distance(p.xyz, worldPos.xyz);
            if (p.a > 0.5 && d <= radius)
                //Return negative distance to indicate a local minimum was found.
                return -1.0; 
            else
                minDist = Math.min(minDist, d);
        }
    return minDist;
}

在第二次测试中找到局部极小值要容易得多,因为您只需要对本地3x3邻域进行采样。

我希望这能帮助你达到预期的渲染效果!

票数 2
EN
页面原文内容由Computer Graphics提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://computergraphics.stackexchange.com/questions/9935

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档