0

我正在开发自己的图形引擎来渲染各种分形(例如我的视频在这里),我目前正在优化我的 Julia Set 配合代码(有关更多详细信息,请参阅这个问题我的项目)。在片段着色器中,我使用了这个函数:

vec3 JuliaMatingLoop(dvec2 z)
{
    ...

    for (int k = some_n; k >= 0; --k)
    {
        // z = z^2
        z = dcproj(c_2(z));
        
        // Mobius Transformation: (ma[k] * z + mb[k]) / (mc[k] * z + md[k])
        z = dcproj(dc_div(cd_mult(ma[k], z) + mb[k], dc_mult(mc[k], z) + md[k]));
    }
    
    ...
}

阅读完这篇文章后,我意识到我正在这段代码中进行 Mobius 转换,并且(从数学上讲)我可以使用矩阵来完成相同的操作。但是,abcd常量都是复数(在我的代码中表示为ma[k]mb[k]mc[k]md[k]),而 GLSL 矩阵中的元素仅包含实数(而不是 vec2)。所以我的问题是:有没有办法使用 GLSL 中的矩阵来优化这些 Mobius 变换?或者任何其他优化这部分代码的方法?

辅助函数(这部分我需要使用双精度,所以我无法通过切换到使用浮点数来优化):

// Squaring
dvec2 c_2(dvec2 c)
{
    return dvec2(c.x*c.x - c.y*c.y, 2*c.x*c.y);
}
// Multiplying
dvec2 dc_mult(dvec2 a, dvec2 b)
{
    return dvec2(a.x*b.x - a.y*b.y, a.x*b.y + a.y*b.x);
}
// Dividing
dvec2 dc_div(dvec2 a, dvec2 b)
{
    double x = b.x * b.x + b.y * b.y;
    return vec2((a.x * b.x + a.y * b.y) / x, (b.x * a.y - a.x * b.y) / x);
    
}
// Riemann Projecting
dvec2 dcproj(dvec2 c)
{
    if (!isinf(c.x) && !isinf(c.y) && !isnan(c.x) && !isnan(c.y))
        return c;
        
    return dvec2(infinity, 0);
}
4

1 回答 1

0

我不确定这是否会有所帮助,但是是的,您可以通过矩阵进行复杂的算术运算。

如果将复数 z 视为具有分量 Re(z)、Im(z) 的实二向量,则

A*z + B ~ (Re(A)  -Im(A) ) * (Re(z)) + (Re(B))
          (Im(A)   Re(A) )   (Im(z))   (Im(B))

当然你真的想要

(A*z + B) / (C*z + D)

如果你计算

A*z+b as (x)
         (y)

C*z+d as (x')
         (y')

那么你寻求的答案是

inv( x' -y') * ( x)
   ( y' x' )   ( y)
i.e
    (1/(x'*x'+y'*y')) * (x'  y') * (x)
                        (-y' x')   (y)

但是,需要注意的一件事是,在这些公式中,就像在您的代码中一样,除法的实现并没有尽可能健壮。问题在于评估 bx * bx + by * by 这可能会溢出到无穷大,或者下溢到 0,即使除法的结果可能非常合理。一个常用的方法是史密斯的方法,例如在这里,如果你搜索“稳健的复数除法”,你会发现更多最近的工作。通常这类事情无关紧要,但如果你迭代到无穷大,它可能会有所作为。

于 2020-08-02T15:33:46.250 回答