На последнем шаге генерация окт-дерева идет не так - PullRequest
0 голосов
/ 08 июня 2018

ПРИМЕЧАНИЕ. ЭТОТ ВОПРОС ДРАСТИЧЕСКИ ИЗМЕНЕН ИЗ ЕГО ОРИГИНАЛЬНОЙ ФОРМЫ

Я пытаюсь создать логарифмический трассировщик лучей, реализуя структуру данных октанового дерева в сочетании с вокселизацией для достижения быстрой трассировки лучей.

В настоящее время у меня возникают проблемы с обнаружением столкновения лучей.

Ожидаемый результат - это вокселизированный Стэнфордский дракон с его картой нормалей.

В настоящее время проблема заключается в том, что некоторые регионы являются прозрачными:

Полный дракон:

Full Dragon

Прозрачные регионы:

enter image description here

Из этих изображений должно быть ясно, что геометрия верна, но проверки коллизий неверны.

В этом процессе участвуют 2 фрагментных шейдера:

Фрагментный шейдер вокселизатора:

#version 430

in vec3 f_pos;
in vec3 f_norm;
in vec2 f_uv;

out vec4 f_color;
struct Voxel
{
    vec4 position;
    vec4 normal;
    vec4 color;
};

struct Node
{
    int children[8];
};

layout(std430, binding = 0) buffer voxel_buffer
{
    Voxel voxels[];
};
layout(std430, binding = 1) buffer buffer_index
{
    uint index;
};
layout(std430, binding = 2) buffer tree_buffer
{
    Node tree[];
};
layout(std430, binding = 3) buffer tree_index
{
    uint t_index;
};

out vec4 fragment_color;

uniform int voxel_resolution;
uniform int cube_dim;

int getVIndex(vec3 position, int level)
{
    float size = cube_dim / pow(2,level);

    int bit2 = int(position.x > size);
    int bit1 = int(position.y > size);
    int bit0 = int(position.z > size);

    return 4*bit2 + 2*bit1 + bit0;
}

void main()
{

    uint m_index = atomicAdd(index, 1);

    voxels[m_index].position = vec4(f_pos*cube_dim,1);
    voxels[m_index].normal = vec4(f_norm,1);
    voxels[m_index].color = vec4(f_norm,1);

    int max_level = int(log2(voxel_resolution));
    int node = 0;
    vec3 corner = vec3(-cube_dim);
    int child;

    for(int level=0; level<max_level-1; level++)
    {
        float size = cube_dim / pow(2,level);
        vec3 corners[] =
            {corner,                    corner+vec3(0,0,size),
            corner+vec3(0,size,0),      corner+vec3(0,size,size),
            corner+vec3(size,0,0),      corner+vec3(size,0,size),
            corner+vec3(size,size,0),   corner+vec3(size,size,size)};

        vec3 offsetPos = (vec3(voxels[m_index].position));
       child = getVIndex(offsetPos-corner, level);

        int mrun = 500;
        while ((tree[node].children[child] <= 0) && (mrun > 0)){
            mrun--;
            if( (atomicCompSwap( tree[node].children[child] , 0 , -1) == 0 ))
            {
                tree[node].children[child] = int(atomicAdd(t_index, 1));
            }
        }

        if(mrun < 1)
            discard;

        if(level==max_level-2)
            break;

        node = tree[node].children[child];

        corner = corners[child];
    }

    tree[node].children[child] = int(m_index);

}

Я понимаю, что логика может быть неясной, поэтому позвольте мне объяснить:

Мы начнем с трехмерного положения voxels[m_index].position = vec4(f_pos*cube_dim,1); И мы знаем, что есть куб с размерами (-cube_dim, -cube_dim, -cube_dim) в (cube_dim, cube_dim, cube_dim) Таким образом, куб, диагонали которого пересекаются в начале координат с длиной стороны 2 * cube_dim.Это было разделено на несколько маленьких кубиков с длиной стороны 2 * cube_dim / voxel_resolution.По сути, это просто куб, разделенный на n раз для создания декартовой сетки.

Используя эту координату, мы начинаем с большого куба, подразделяя его на 8 подпространств равного размера и определяя, какое из этих подпространств содержит координату.

Мы будем делать это до тех пор, пока не найдем самый маленький прямоугольник с позицией.

Raytracer

 #version 430

in vec2 f_coord;

out vec4 fragment_color;

struct Voxel
{
    vec4 position;
    vec4 normal;
    vec4 color;
};

struct Node
{
    int children[8];
};

layout(std430, binding = 0) buffer voxel_buffer
{
    Voxel voxels[];
};
layout(std430, binding = 1) buffer buffer_index
{
    uint index;
};
layout(std430, binding = 2) buffer tree_buffer
{
    Node tree[];
};
layout(std430, binding = 3) buffer tree_index
{
    uint t_index;
};

uniform vec3 camera_pos;
uniform float aspect_ratio;
uniform float cube_dim;
uniform int voxel_resolution;

float planeIntersection(vec3 origin, vec3 ray, vec3 pNormal, vec3 pPoint)
{
    pNormal = normalize(pNormal);
    return (dot(pPoint,pNormal)-dot(pNormal,origin))/dot(ray,pNormal);
}

#define EPSILON 0.001
bool inBoxBounds(vec3 corner, float size, vec3 position)
{
    bool inside = true;
    position-=corner;

    for(int i=0; i<3; i++)
    {
        inside = inside && (position[i] > -EPSILON);
        inside = inside && (position[i] < size+EPSILON);
    }

    return inside;
}


float boxIntersection(vec3 origin, vec3 dir, vec3 corner0, float size)
{
    dir = normalize(dir);
    vec3 corner1 = corner0 + vec3(size,size,size);

    vec3 normals[6] =
    { vec3(-1,0,0), vec3(0,-1,0), vec3(0,0,-1), vec3(1,0,0), vec3(0,1,0), vec3(0,0,1) };

    float coeffs[6];

    for(uint i=0; i<3; i++)
        coeffs[i] = planeIntersection(origin, dir, normals[i], corner0);
    for(uint i=3; i<6; i++)
        coeffs[i] = planeIntersection(origin, dir, normals[i], corner1);

    float t = 1.f/0.f;

    for(uint i=0; i<6; i++){
        coeffs[i] = coeffs[i] < 0 ? 1.f/0.f : coeffs[i];
        t = inBoxBounds(corner0,size,origin+dir*coeffs[i]) ? min(coeffs[i],t) : t;
    }

    return t;
}

void sort(float elements[8], int indices[8], vec3 vectors[8])
{
    for(uint i=0; i<8; i++)
    {
        for(uint j=i; j<8; j++)
        {
            if(elements[j] < elements[i])
            {
                float swap = elements[i];
                elements[i] = elements[j];
                elements[j] = swap;

                int iSwap = indices[i];
                indices[i] = indices[j];
                indices[j] = iSwap;

                vec3 vSwap = vectors[i];
                vectors[i] = vectors[j];
                vectors[j] = vSwap;
            }
        }
    }
}

int getVIndex(vec3 position, int level)
{
    float size = cube_dim / pow(2,level);

    int bit2 = int(position.x > size);
    int bit1 = int(position.y > size);
    int bit0 = int(position.z > size);

    return 4*bit2 + 2*bit1 + bit0;
}

#define MAX_TREE_HEIGHT 11
int nodes[8*MAX_TREE_HEIGHT];
int levels[8*MAX_TREE_HEIGHT];
vec3 positions[8*MAX_TREE_HEIGHT];
int sp=0;

void push(int node, int level, vec3 corner)
{
    nodes[sp] = node;
    levels[sp] = level;
    positions[sp] = corner;
    sp++;
}
void main()
{
    vec3 r = vec3(f_coord.x, f_coord.y, 1.f/tan(radians(40)));
    r.y/=aspect_ratio;
    vec3 dir = r;
    r += vec3(0,0,-1.f/tan(radians(40))) + camera_pos;

    fragment_color = vec4(0);
    //int level = 0;
    int max_level = int(log2(voxel_resolution));
    push(0,0,vec3(-cube_dim));
    float tc = 1.f;
    int level=0;
    int node=0;
    do
    {
        sp--;
        node = nodes[sp];
        level = levels[sp];
        vec3 corner = positions[sp];

        float size = cube_dim / pow(2,level);
        vec3 corners[] =
            {corner,                        corner+vec3(0,0,size),
            corner+vec3(0, size,0),         corner+vec3(0,size,size),
            corner+vec3(size,0,0),          corner+vec3(size,0,size),
            corner+vec3(size,size,0),       corner+vec3(size,size,size)};

        float t = boxIntersection(r, dir, corner, size*2);
        if(!isinf(t))
            tc *= 0.9f;

        float coeffs[8];
        for(int child=0; child<8; child++)
        {
            if(tree[node].children[child]>0)
                coeffs[child] = boxIntersection(r, dir, corners[child], size);
            else
                coeffs[child] = 1.f/0.f;
        }
        int indices[8] = {0,1,2,3,4,5,6,7};
        sort(coeffs, indices, corners);

        for(uint i=7; i>=0; i--)
        {
            if(!isinf(coeffs[i]))
            {
                push(tree[node].children[indices[i]],
                    level+1, corners[i]);
            }
        }
    }while(level < (max_level-1) && sp>0);

    if(level==max_level-1)
    {
        fragment_color = abs(voxels[node].normal);
    }

    else
    {
        fragment_color=vec4(tc);
    }

}
}

Здесь мы начнем с самого большого куба, проверяя пересечения с каждым набором8 детей (8 кубов, полученных в результате разделения куба).Каждый раз, когда мы успешно обнаруживаем столкновение, мы движемся вниз по дереву, пока не достигнем самого низкого уровня, который описывает фактическую геометрию, и не раскрасим сцену, основываясь на этом.

Отладка и проблема

важная часть состоит в том, что есть 2 буфера, один для хранения дерева, кроме листьев, и один для хранения листьев.

Таким образом, и при вокселизации, и при трассировке лучей последний слой должен обрабатываться по-разному.

Проблемы прозрачности, которые я заметил, следующие:

  • Это происходит только на плоскостях, выровненных по декартовой сетке

  • Кажется, это происходит, когда луч движется в отрицательном направлении (вниз или влево).(По крайней мере, это мое впечатление, но оно не на 100%
    точно)

Я не уверен, что я делаю неправильно.

РЕДАКТИРОВАТЬ:

Оригинальная проблема, кажется, была исправлена, однако raytracer все еще прослушивается.Я отредактировал вопрос, чтобы отобразить текущее состояние проблемы.

1 Ответ

0 голосов
/ 09 июня 2018

Ошибка происходит из-за функции сортировки, как кто-то в комментариях, упомянутой, хотя и не по тем же причинам.

То, что произошло, я думал, что функция сортировки изменила бы переданные ей массивы, но этопохоже, что данные копируются, поэтому ничего не возвращается.

Другими словами:

void sort(float elements[8], int indices[8], vec3 vectors[8])
{
    for(uint i=0; i<8; i++)
    {
        for(uint j=i; j<8; j++)
        {
            if((elements[j] < elements[i]))
            {
                float swap = elements[i];
                elements[i] = elements[j];
                elements[j] = swap;

                int iSwap = indices[i];
                indices[i] = indices[j];
                indices[j] = iSwap;

                vec3 vSwap = vectors[i];
                vectors[i] = vectors[j];
                vectors[j] = vSwap;
            }
        }
    }
}

Не возвращает правильные значения внутри элементов, индексов и векторов, поэтому вызов этогофункция не делает ничего, кроме ненужных циклов вычислений.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...