How am I ending up having a better phantom resolution?

I am rendering a voxel object (human body) which is represented by a 3d array[x][y][z]. Each voxel is represented by 8 vertices and each vertice has 3 coordinates (x,y and z) in opengl coordinate system. I did not know if I should define a voxel size in mm or sm (meaning if 1 in x, y or z direction should correspond to 1sm or 1mm) so I decide to try both ways.

Following code is responsible for transfering from m to sm/mm

``````// phantom->phantomSize[0] returns value in m
// to get value in sm multiply value by 100 and not 1000
voxelSizeX = phantom->phantomSize[0] * 1000 / xMax; // in mm
voxelSizeY = phantom->phantomSize[1] * 1000 / yMax;
voxelSizeZ = phantom->phantomSize[2] * 1000 / zMax;
``````

Size of a voxel sm/mm:

``````1.775mm/0.1775sm
1.775mm/0.1775sm
4.84mm/0.484sm
``````

Coordinates in mm:

``````342.575 120.7 0
342.575 120.7 4.84
342.575 122.475 0
342.575 122.475 4.84
``````

Coordinates in sm:

``````34.2575 12.07 0
34.2575 12.07 0.484
34.2575 12.2475 0
34.2575 12.2475 0.484 //and so on
``````

Then I am scaling the phantom with the help of glm library as phantom is to big and do not fit into screen:

``````trans = glm::scale(trans, glm::vec3(0.01, 0.01, 0.01)); // if voxel is in mm
trans = glm::scale(trans, glm::vec3(0.1, 0.1, 0.1)); // if voxel is in sm
``````

And here are results:

1. voxel size is in sm

2. voxel size is in mm![in mm|625x492]

Question: How I am ending up with a better resolution when a voxel size is defined in mm? Should not the result be the same regardles if a vosel is defined in sm or mm as later I am scaling them using glm?

voxel size is in mm

Why do you think you’re “ending up with a better resolution”. It doesn’t look to me like you are. It appears you’re just getting differences in rasterization possibly due to differences in model positioning or rotation w.r.t. the view frustum.

Also, before it even makes sense to talk about your question, you need to describe a bit more about how you’re rendering this voxel grid.

And if the numbers you’ve listed above are correct and “mm = millimeter” instead of “sm” I think you mean “cm” (centimeter) (see Unit_of_length#SI (Wikipedia)).

Blockquote And if the numbers you’ve listed above are correct and “mm = millimeter” instead of “sm” I think you mean “cm” (centimeter) (see [Unit_of_length#SI]

Yes, I meant cm (centimeter). Sorry for that.

Basically here I am creating vertices and indices and writing them to 2 txt files vertices.txt and indices.txt

``````for (int y = 0; y < yMax; y++)
{
for (int x = 0; x < xMax; x++)
{
if (phantom->voxel[x][y][z] == emptyVoxel) // checking if voxel is not empty. Empty voxels have value 255 in them
{
continue;
}
else
{
if ((x != 0 && x != (xMax - 1)) && (y != 0 && y != (yMax - 1)) && (z != 0 && z != (zMax - 1)) &&
(phantom->voxel[x + 1][y][z] != emptyVoxel) && (phantom->voxel[x - 1][y][z] != emptyVoxel) && (phantom->voxel[x][y + 1][z] != emptyVoxel) &&
(phantom->voxel[x][y - 1][z] != emptyVoxel) && (phantom->voxel[x][y][z + 1] != emptyVoxel) && (phantom->voxel[x][y][z - 1] != emptyVoxel))
// checking if a voxel is surrounded from all sides by non empty voxes. If its surrounded then we do not need to create vertices and indices for it.
{
continue;
}
// here I am creating vertices (that contain only coordinates) and multiplying each coordinate by voxelSize in order to scale phantom to more human like scale.
verticies_out_file << x * voxelSizeX << " " << y * voxelSizeY << " " << z * voxelSizeZ << std::endl;
verticies_out_file << x * voxelSizeX << " " << y * voxelSizeY << " " << (z + 1) * voxelSizeZ << std::endl;
verticies_out_file << x * voxelSizeX << " " << (y + 1) * voxelSizeY << " " << z * voxelSizeZ << std::endl;
verticies_out_file << x * voxelSizeX << " " << (y + 1) * voxelSizeY << " " << (z + 1) * voxelSizeZ << std::endl;
verticies_out_file << (x + 1) * voxelSizeX << " " << y * voxelSizeY << " " << z * voxelSizeZ << std::endl;
verticies_out_file << (x + 1) * voxelSizeX << " " << y * voxelSizeY << " " << (z + 1) * voxelSizeZ << std::endl;
verticies_out_file << (x + 1) * voxelSizeX << " " << (y + 1) * voxelSizeY << " " << z * voxelSizeZ << std::endl;
verticies_out_file << (x + 1) * voxelSizeX << " " << (y + 1) * voxelSizeY << " " << (z + 1) * voxelSizeZ << std::endl;

if (x != 0 && x != (xMax - 1))
{
if (phantom->voxel[x - 1][y][z] != emptyVoxel)
{
indicies_out_file << (elements * 8) << " " << (elements * 8 + 2) << " " << (elements * 8 + 3) << " "
<< (elements * 8) << " " << (elements * 8 + 1) << " "<< (elements * 8 + 3) << std::endl; // left face
}
if (phantom->voxel[x + 1][y][z] != emptyVoxel)
{
indicies_out_file << (elements * 8 + 4) << " " << (elements * 8 + 5) << " "<< (elements * 8 + 7) << " "
<< (elements * 8 + 4) << " "<< (elements * 8 + 6) << " " << (elements * 8 + 7) << std::endl; // right face
}
}
else
{
if (x == 0)
{
indicies_out_file << (elements * 8) << " " << (elements * 8 + 2) << " "<< (elements * 8 + 3) << " "
<< (elements * 8) << " "<< (elements * 8 + 1) << " "<< (elements * 8 + 3) << std::endl; // left face
}
if (x == (xMax - 1))
{
indicies_out_file << (elements * 8 + 4) << " "<< (elements * 8 + 5) << " "<< (elements * 8 + 7) << " "
<< (elements * 8 + 4) << " " << (elements * 8 + 6) << " " << (elements * 8 + 7) << std::endl; // right face
}
}

if (y != 0 && y != (yMax - 1))
{
if (phantom->voxel[x][y - 1][z] != emptyVoxel)
{
indicies_out_file << (elements * 8 + 1) << " " << (elements * 8 + 5) << " "<< (elements * 8 + 4) << " "
<< (elements * 8 + 1) << " " << (elements * 8) << " "<< (elements * 8 + 4) << std::endl; // bottom face
}
if (phantom->voxel[x][y + 1][z] != emptyVoxel)
{
indicies_out_file << (elements * 8 + 2) << " " << (elements * 8 + 3) << " " << (elements * 8 + 7) << " "
<< (elements * 8 + 2) << " " << (elements * 8 + 6) << " " << (elements * 8 + 7) << std::endl; // top face
}
}
else
{
if (y == 0)
{
indicies_out_file << (elements * 8 + 1) << " " << (elements * 8 + 5) << " " << (elements * 8 + 4) << " "
<< (elements * 8 + 1) << " " << (elements * 8) << " " << (elements * 8 + 4) << std::endl; // bottom face
}

if (y == (yMax - 1))
{
indicies_out_file << (elements * 8 + 2) << " " << (elements * 8 + 3) << " " << (elements * 8 + 7) << " "
<< (elements * 8 + 2) << " " << (elements * 8 + 6) << " " << (elements * 8 + 7) << std::endl; // top face
}
}

if (z != 0 && z != (zMax - 1))
{
if (phantom->voxel[x][y][z - 1] != emptyVoxel)
{
indicies_out_file << (elements * 8) << " " << (elements * 8 + 4) << " " << (elements * 8 + 6) << " "
<< (elements * 8) << " " << (elements * 8 + 2) << " " << (elements * 8 + 6) << std::endl;  // front face
}

if (phantom->voxel[x][y][z + 1] != emptyVoxel)
{
indicies_out_file << (elements * 8 + 1) << " " << (elements * 8 + 5) << " " << (elements * 8 + 7) << " "
<< (elements * 8 + 1) << " " << (elements * 8 + 3) << " " << (elements * 8 + 7) << std::endl; // back face
}
}
else
{
if (z == 0)
{
indicies_out_file << (elements * 8) << " " << (elements * 8 + 4) << " " << (elements * 8 + 6) << " "
<< (elements * 8) << " " << (elements * 8 + 2) << " " << (elements * 8 + 6) << std::endl;  // front face
}

if (z == (zMax - 1))
{
indicies_out_file << (elements * 8 + 1) << " " << (elements * 8 + 5) << " " << (elements * 8 + 7) << " "
<< (elements * 8 + 1) << " " << (elements * 8 + 3) << " " << (elements * 8 + 7) << std::endl; // back face
}
}

elements++;
}
}
}
}
``````

In my Mesh class I am reading from 2 txt files vertices.txt and indices.txt first by allocating buffer and uploading whole files in order to speed up reading process as each file contains roughly 1 million lines. Then by reading character by character I am storing data in 2 vectors indices and vertices.

``````#include "Mesh.h"
#include <iostream>
#include <sstream>
#include <fstream>
#include <math.h>

Mesh::Mesh()
{
}

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

{
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.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:
}
}

delete[] buffer;
}
}

{
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.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:
}
}

delete[] buffer;
}
}

{

initBuffers();

}

void Mesh::draw()
{

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

Draw method

``````void MyGLCanvas::draw(wxDC& dc)
{
glm::vec3 modelPos = glm::vec3(0.0f, -10.0f, -50.0f);
glm::mat4 model, view;

model = glm::translate(model, modelPos);
view = fpsCamera->getViewMatrix();
projection = glm::perspective(glm::radians(fpsCamera->getFOV()), (float)(windowWidth / windowHeight), 0.1f, 100.0f);

glm::mat4 trans;
trans = glm::rotate(trans, 30.0f, glm::vec3(0.0f, 1.0f, 0.0f)); // after rotation phantom will face the camera
trans = glm::scale(trans, glm::vec3(0.01, 0.01, 0.01));

glClearStencil(0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

shaderProgram.setUniform("color", glm::vec3(0.310f, 0.747f, 0.185f)); //ignore color for now

mesh->draw()

//degree += 0.05f;
SwapBuffers();
}
``````

Nothing stands out.

How many fractional digits are you writing? The default precision is 6 digits which is more than adequate for either case, but if it’s been reduced (with `std::setprecision`) and you’re using fixed (as opposed to scientific) notation, you need to consider that values in mm will have ten times the precision of values in cm.

Also: is there a reason for parsing the numbers yourself rather than just using `>>`?

Blockquote Also: is there a reason for parsing the numbers yourself rather than just using `>>` ?

Reading from buffer is much faster that is why I have to parse numbers by reading each individual character.

This topic was automatically closed 183 days after the last reply. New replies are no longer allowed.