Как я могу определить, пересекается ли луч с моим фантомным объектом? - PullRequest
0 голосов
/ 19 июня 2020

В своей программе я визуализирую человеческое тело (фантом). Фантомные данные хранятся в txt файлах vertices.txt (файлы вершин содержат координаты x, y и z каждой вершины, которую нужно нарисовать) и index.txt. В настоящее время я пытаюсь разработать фантомное выделение, чтобы я мог изменять положение объекта в пространстве или вращаться вокруг оси. Но проблема в том, что я не знаю, как определить, пересекается ли отброшенный луч с фантомом.

Вопрос: как я могу определить, пересекается ли луч с моим фантомным объектом?

Код для литья лучей:

glm::vec3 MyGLCanvas::calculateMouseRay(glm::mat4 projectionMatrix)
{
    GLfloat mouseX = wxGetMousePosition().x;
    GLfloat mouseY = wxGetMousePosition().y;

    glm::vec2 normalizedCoords = getNormmalizedDeviceCoords(mouseX, mouseY);
    glm::vec4 clipCoords = glm::vec4(normalizedCoords.x, normalizedCoords.y, -1.0f, 1.0f);
    glm::vec4 eyeCoords = toEyeCoords(clipCoords, projectionMatrix);
    glm::vec3 worldRay = toWorldCoords(eyeCoords);

    return worldRay;
}

glm::vec4 MyGLCanvas::toEyeCoords(glm::vec4 clipCoords, glm::mat4 projectionMatrix)
{
    glm::mat4 invertedProjection = glm::inverse(projectionMatrix);
    glm::vec4 eyeCoords = invertedProjection * clipCoords;

    return glm::vec4(eyeCoords.x, eyeCoords.y, -1.0f, 0.0f);
}

glm::vec3 MyGLCanvas::toWorldCoords(glm::vec4 eyeCoords)
{
    glm::mat4 invertedView = glm::inverse(fpsCamera->getViewMatrix());
    glm::vec4 rayWorld = invertedView * eyeCoords;
    glm::vec3 mouseRay = glm::vec3(rayWorld.x, rayWorld.y, rayWorld.z);
    mouseRay = glm::normalize(mouseRay);

    return mouseRay;
}

glm::vec2 MyGLCanvas::getNormmalizedDeviceCoords(GLfloat mouseX, GLfloat mouseY)
{
    GLfloat x = (2.0f * mouseX) / windowWidth - 1.0f;
    GLfloat y = 1.0f - (2.0f * mouseY) / windowHeight;
    return glm::vec2(x, y);
}

Код для загрузки моего фантомного объекта:

#include <sstream>
#include <fstream>
#include <math.h>

Mesh::Mesh()
{
    loaded = false;
}

Mesh::~Mesh()
{
    glDeleteVertexArrays(1, &vao);
    glDeleteBuffers(1, &vbo);
    glDeleteBuffers(1, &ibo);
}

void Mesh::loadVertices(std::string fileName)
{
    double item = 0;
    int n = 0, x = 0, y = 0;
    bool dotEncountered = false;
    int numbersAfterDot = 0;
    std::ifstream is(fileName, std::ifstream::binary);

    if (is) {
        is.seekg(0, is.end);
        int length = is.tellg();
        is.seekg(0, is.beg);

        char* buffer = new char[length];

        is.read(buffer, length);

        is.close();

        for (unsigned int i = 0; i < is.gcount(); i++)
        {
            switch (buffer[i])
            {
            case '\r':
                break;
            case '\n':
            {
                vertices.push_back(glm::vec3(y, item, x));
                dotEncountered = false;
                numbersAfterDot = 0;
                n = 0;
                item = 0;
                break;
            }
            case ' ':
            {
                n++;
                if (n == 1)
                {
                    x = item;
                    dotEncountered = false;
                    numbersAfterDot = 0;
                }
                else
                {
                    dotEncountered = false;
                    numbersAfterDot = 0;
                    y = item;
                }

                dotEncountered = false;
                numbersAfterDot = 0;
                item = 0;
                break;
            }
            case '.':
                dotEncountered = true;
                break;
            case '0': case '1': case '2': case '3':
            case '4': case '5': case '6': case '7':
            case '8': case '9':
                if (!dotEncountered)
                {
                    item = 10 * item + buffer[i] - '0';
                    break;
                }
                else
                {
                    numbersAfterDot++;
                    item += (double) (buffer[i] - '0') / pow(10, numbersAfterDot);
                    break;
                }
            default:
                std::cerr << "Bad format\n";
            }
        }

        delete[] buffer;
    }
}

void Mesh::loadIndices(std::string fileName)
{
    int item = 0;
    std::ifstream is(fileName, std::ifstream::binary);

    if (is) {
        is.seekg(0, is.end);
        int length = is.tellg();
        is.seekg(0, is.beg);

        char* buffer = new char[length];

        is.read(buffer, length);

        is.close();

        for (unsigned int i = 0; i < is.gcount(); i++)
        {
            switch (buffer[i])
            {
            case '\r':
                break;
            case '\n':
            {
                indicies.push_back(item);
                item = 0;
                break;
            }
            case ' ':
            {
                indicies.push_back(item);
                item = 0;
                break;
            }
            case '0': case '1': case '2': case '3':
            case '4': case '5': case '6': case '7':
            case '8': case '9':
                item = 10 * item + buffer[i] - '0';
                break;
            default:
                std::cerr << "Bad format\n";
            }
        }

        delete[] buffer;
    }
}


bool Mesh::loadOBJ()
{
    loadVertices("Phantom Data/FA_vertices.txt");
    loadIndices("Phantom Data/FA_indices.txt");

    initBuffers();

    return (loaded = true);
}

void Mesh::draw()
{
    if (!loaded) return;


    glBindVertexArray(vao);
    glDrawElements(GL_TRIANGLES, indicies.size(), GL_UNSIGNED_INT, nullptr);
    glBindVertexArray(0);
}

void Mesh::initBuffers()
{
    glGenVertexArrays(1, &vao);
    glBindVertexArray(vao);

    glGenBuffers(1, &vbo);
    glBindBuffer(GL_ARRAY_BUFFER, vbo);
    glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(glm::vec3), &vertices[0], GL_STATIC_DRAW);

    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(glm::vec3), NULL);
    glEnableVertexAttribArray(0);

    glGenBuffers(1, &ibo);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, indicies.size() * sizeof(GLuint), &indicies[0], GL_STATIC_DRAW);

    glBindVertexArray(0);
}

Изображение нарисованного фантома: enter image description here

Пример из вершин .txt:

273.536 185.919 1752 // z, y and x coordinates. This file contains 2 million lines
273.536 185.919 1760
273.536 188.056 1752
273.536 188.056 1760
273.536 185.919 1752
273.536 185.919 1760
273.536 188.056 1752
273.536 188.056 1760
275.673 185.919 1752
275.673 185.919 1760
275.673 188.056 1752

Пример из index.txt:

4 5 7 4 6 7
2 3 7 2 6 7
0 4 6 0 2 6
8 10 11 8 9 11
12 13 15 12 14 15
10 11 15 10 14 15
8 12 14 8 10 14
...