有效地计算体素数据的梯度

Mor*_*bel 5 c++ raytracing voxel marching-cubes

计算固定大小的体素数据的梯度的最有效方法是什么,例如下面的源代码.请注意,我需要在空间的任何位置使用渐变.渐变将用于估计行进立方体实现中的法线.

#import <array>

struct VoxelData {
    VoxelData(float* data, unsigned int xDim, unsigned int yDim, unsigned int zDim)
    :data(data), xDim(xDim), yDim(yDim), zDim(zDim)
    {}

    std::array<float,3> get_gradient(float x, float y, float z){
        std::array<float,3> res;
        // compute gradient efficiently
        return res;
    }

    float get_density(int x, int y, int z){
        if (x<0 || y<0 || z<0 || x >= xDim || y >= yDim || z >= zDim){
            return 0;
        }
        return data[get_element_index(x, y, z)];
    }

    int get_element_index(int x, int y, int z){
        return x * zDim * yDim + y*zDim + z;
    }

    const float* const data;

    const unsigned int xDim;
    const unsigned int yDim;
    const unsigned int zDim;

};
Run Code Online (Sandbox Code Playgroud)

更新1 可以在此处找到问题的演示项目:

https://github.com/mortennobel/OpenGLVoxelizer

目前输出如下图所示(基于MooseBoys代码):

更新2 我正在寻找的解决方案必须提供相当准确的渐变,因为它们在可视化中用作法线,必须避免像下面那样的视觉文物.

在此输入图像描述

来自用户示例的Update 2解决方案是:

在此输入图像描述

Moo*_*oys 2

以下产生线性插值梯度场:

std::array<float,3> get_gradient(float x, float y, float z){
    std::array<float,3> res;
    // x
    int xi = (int)(x + 0.5f);
    float xf = x + 0.5f - xi;
    float xd0 = get_density(xi - 1, (int)y, (int)z);
    float xd1 = get_density(xi, (int)y, (int)z);
    float xd2 = get_density(xi + 1, (int)y, (int)z);
    res[0] = (xd1 - xd0) * (1.0f - xf) + (xd2 - xd1) * xf; // lerp
    // y
    int yi = (int)(y + 0.5f);
    float yf = y + 0.5f - yi;
    float yd0 = get_density((int)x, yi - 1, (int)z);
    float yd1 = get_density((int)x, yi, (int)z);
    float yd2 = get_density((int)x, yi + 1, (int)z);
    res[1] = (yd1 - yd0) * (1.0f - yf) + (yd2 - yd1) * yf; // lerp
    // z
    int zi = (int)(z + 0.5f);
    float zf = z + 0.5f - zi;
    float zd0 = get_density((int)x, (int)y, zi - 1);
    float zd1 = get_density((int)x, (int)y, zi);
    float zd2 = get_density((int)x, (int)y, zi + 1);
    res[2] = (zd1 - zd0) * (1.0f - zf) + (zd2 - zd1) * zf; // lerp
    return res;
}
Run Code Online (Sandbox Code Playgroud)

  • @Mortennobel您要求一种有效的方法,而不是准确的方法(或者您所说的视觉上更平滑),也许您可​​以将其添加为原始问题的评论? (2认同)