C++ 返回未定义结果的GLSL日志

C++ 返回未定义结果的GLSL日志,c++,glsl,vulkan,C++,Glsl,Vulkan,我正试图画曼德布罗特集。我已经在CPU上创建了算法,但是现在我想在GPU上重现它,但是代码的行为不同 在CPU程序中,有一次,我使用std::abs(z),其中z是一个复数,并将值写入屏幕上的绿色通道中 在GPU上,我使用相同的z并调用以下函数(Vulkan、GLSL): 当我将颜色(z)写入绿色通道时,我得到的图像与CPU程序的图像完全相同,因此代码的工作方式完全相同,至少在这一点上是如此 接下来,我将CPU代码改为采用std::log(std::abs(z))/20,并将其置于绿色通道中。这

我正试图画曼德布罗特集。我已经在CPU上创建了算法,但是现在我想在GPU上重现它,但是代码的行为不同

在CPU程序中,有一次,我使用std::abs(z),其中z是一个复数,并将值写入屏幕上的绿色通道中

在GPU上,我使用相同的z并调用以下函数(Vulkan、GLSL):

当我将颜色(z)写入绿色通道时,我得到的图像与CPU程序的图像完全相同,因此代码的工作方式完全相同,至少在这一点上是如此

接下来,我将CPU代码改为采用
std::log(std::abs(z))/20
,并将其置于绿色通道中。这是我得到的图像(mandelbrot集合中的NUBMER为白色):

您可以看到,绿色永远不会被剪裁,因此每个像素的结果都在范围(0,1)内的某个位置

然后我将GPU代码更改为:

double module(dvec2 z) {
    return sqrt(z.x * z.x + z.y * z.y);
}

double color(z) {
    return log(module(z));
}
我将
color(z)/20
写入绿色通道。这是生成的图像:


正如您所见,
color(z)/20
的值必须是当您要求GPU计算一个非常大的对数时,GPU实际上并不喜欢。从我收集的资料来看,log(实际上是ln)被实现为泰勒级数。这是不幸的,因为它包含n个成员的n次方多项式

但是,如果您将一个数字表示为
x=尾数*2^exp
,则可以通过以下公式获得
ln(x)

ln(x) = exp * ln(2) + ln(mantissa)
不管x是什么,尾数都应该小得多。下面是片段着色器的函数:

float ln(float z) {
    int integerValue = floatBitsToInt(z);
    int exp = ((integerValue >> mantissaBits) & (1 << expBits) - 1)
              - ((1 << (expBits - 1)) - 1);

    integerValue |= ((1 << expBits) - 1) << mantissaBits;
    integerValue &= ~(1 << (mantissaBits + expBits - 1));

    return exp * log2 + log(intBitsToFloat(integerValue));
}
float ln(float z){
int integerValue=floatBitsToInt(z);
int exp=((integerValue>>尾数)和(1)
double color(z) {
    return log(module(z)) + 0.5;
}
double color(z) {
    return log(module(z));
}
ln(x) = exp * ln(2) + ln(mantissa)
float ln(float z) {
    int integerValue = floatBitsToInt(z);
    int exp = ((integerValue >> mantissaBits) & (1 << expBits) - 1)
              - ((1 << (expBits - 1)) - 1);

    integerValue |= ((1 << expBits) - 1) << mantissaBits;
    integerValue &= ~(1 << (mantissaBits + expBits - 1));

    return exp * log2 + log(intBitsToFloat(integerValue));
}