0

In my program I am rendering a human body (phantom). Phantom data is stored in txt files vertices.txt (vertices files contain x, y and z coordinates of each vertice that should be drawn) and indices.txt. Currently I am trying to develop phantom selection so I could change object position in space or rotate around axis. But the problem is that I do not know how to determine if casted ray intersects with phantom.

Quesition: How can I determine if ray intersects with my phantom object?

Code for ray casting:

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);
}

Code for loading my phantom object:

#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);
}

Image of phantom that is drawn: enter image description here

Example from vertices.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

Example from indices.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
Elnur
  • 119
  • 1
  • 5
  • Are you looking for a ray-triangle intersection test? You can look that one up on wikipedia yourself, notice that you already have all the necessary information to do this in `vertices` and `indices`. Or are you looking for a more complex spatial subdivision scheme? If so what did you try so far? Where are you stuck? – BeyelerStudios Jun 19 '20 at 16:42
  • @BeyelerStudios the problem is that I do not know how to proceed. My human phantom consists of hundreds thousands of triangles how do you know with which triangle did ray intersect. How do you get coordinates of a triangle in order to determine if ray intersects with it? – Elnur Jun 19 '20 at 17:20
  • 2
    You should proceed step by step: first implement a triangle-ray test, iterate over all your triangles and make sure your basics are working. There are many ways of accelerating picking on an object: preprocess your object, extracting the silhouette if your camera stays static, reducing the polycount, building up a spatial subdivision structure for faster querying, etc... look at what fits your situation, try it first, then ask a specific question here on SO. [edit]There are also many libraries out there to help you with that, but this is not a library suggestion site.[/edit] – BeyelerStudios Jun 19 '20 at 17:26
  • 1
    @BeyelerStudios so that means that I have to loop through vertices.txt and indices.txt and then test for each individual triangle if end point of a ray is located inside of a triangle? – Elnur Jun 19 '20 at 17:37
  • render index buffer that stores the point/face index instead of color ... then just use `glReadPixels` on mouse position and render exactly which point/face is under mouse (in `O(1)`) ...see [OpenGL 3D-raypicking with high poly meshes](https://stackoverflow.com/a/51764105/2521214) however STENCIL is just 8bit so you either render to texture or use screen buffer store to memory and then render coloros ... btw add lighting and normals it would look much better – Spektre Jun 20 '20 at 08:49

0 Answers0