I am trying to understand this function, but I can't seem to follow how this code does its thing.
I am hoping someone can walk me through this so I can understand what's going on.
void mountain::LoadData(const char* heightmap_filename)
{
heightmap = cv::imread(heightmap_filename, 0);
heightmap_rows = heightmap.rows;
heightmap_cols = heightmap.cols;
for (int i = 0; i < heightmap.rows; i )
height.push_back(vector<float>(heightmap_cols, 0));
for (int u = 0; u < heightmap_rows; u )
{
for (int v = 0; v < heightmap_cols; v )
{
height[u][v] = heightmap.at<uchar>(u, v);
Points.push_back(BROAD_CONTROLLER * (u - 128));
Points.push_back(BROAD_CONTROLLER * (v - 128));
Points.push_back(HEIGHT_CONTROLLER * height[u][v]);
Points.push_back((float)u / 255.);
Points.push_back((float)v / 255.);
}
}
for (int row = 1; row < heightmap_rows; row )
{
for (int col = 1; col < heightmap_cols; col )
{
indices.push_back((row - 1) * heightmap_cols col - 1);
indices.push_back((row - 1) * heightmap_cols col);
indices.push_back(row * heightmap_cols col - 1);
indices.push_back(row * heightmap_cols col - 1);
indices.push_back((row - 1) * heightmap_cols col);
indices.push_back(row * heightmap_cols col);
}
}
}
May I know what is the Points vector is inserting?
Points.push_back(BROAD_CONTROLLER * (u - 128));
Points.push_back(BROAD_CONTROLLER * (v - 128));
Points.push_back(HEIGHT_CONTROLLER * height[u][v]);
Points.push_back((float)u / 255.);
Points.push_back((float)v / 255.);
and what is the indices vector is inserting?
indices.push_back((row - 1) * heightmap_cols col - 1);
indices.push_back((row - 1) * heightmap_cols col);
indices.push_back(row * heightmap_cols col - 1);
indices.push_back(row * heightmap_cols col - 1);
indices.push_back((row - 1) * heightmap_cols col);
indices.push_back(row * heightmap_cols col);
This is the function to get silhouette, but I don't get it how does this function work.
void mountain::FindSilhouette()
{
int count = 0;
for (int i = 0; i < Points.size() / 5; i )
{
if (abs(Points[5 * i 2] - SEALEVEL) < 2)
{
slet buffer(Points[5 * i], Points[5 * i 1], Points[5 * i 2]);
buffer.num = count;
silhouette.push_back(buffer);
count ;
}
}
}
CodePudding user response:
Points.push_back(BROAD_CONTROLLER * (u - 128));
Points.push_back(BROAD_CONTROLLER * (v - 128));
Points.push_back(HEIGHT_CONTROLLER * height[u][v]);
Points.push_back((float)u / 255.);
Points.push_back((float)v / 255.);
Points
contains successive groups of 5 floats. The first two are x
and y
, the two coordinate that the u
and v
are iterating over. The third one is z
, which is looked up in the heightmap (height
). The fourth and fifth are most likely uv
texture coordinates.
indices.push_back((row - 1) * heightmap_cols col - 1);
indices.push_back((row - 1) * heightmap_cols col);
indices.push_back(row * heightmap_cols col - 1);
indices.push_back(row * heightmap_cols col - 1); // <- repeats third
indices.push_back((row - 1) * heightmap_cols col); // <- repeats second
indices.push_back(row * heightmap_cols col);
The indices
are the indices to use to draw two triangles, in this fashion:
0--2
| / 3
|/ /|
1 / |
4--5
That's why 3 (the fourth) repeats 2 (the third), and 4 repeats 1. heightmap_cols
is the number of column in the heightmap, row and col the current position. Basically, it builds a list of indices to lookup the position as the heightmap is drawn as a set of pair of triangles. Each pair forms a square.
CodePudding user response:
May I know what is the Points vector is inserting?
It's effectively inserting a 3D vertex, and a 2D texture coordinate. i.e.
struct Vertex {
// the 3D position of the vertex
float x;
float y;
float z;
// the 2D texture coordinate
float u;
float u;
};
It generates one of these structures for every single pixel in the input image. I actually think the code is wrong, because it seems to assume images can only ever be 256x256 pixels? I'd probably replace the hardcoded 255 and 128 values with the following:
// read pixel from image
height[u][v] = heightmap.at<uchar>(u, v);
// x & y coordinates
Points.push_back(BROAD_CONTROLLER * (u - heightmap_rows/2));
Points.push_back(BROAD_CONTROLLER * (v - heightmap_cols/2)));
Points.push_back(HEIGHT_CONTROLLER * height[u][v]);
Points.push_back((float)u / float(heightmap_rows - 1));
Points.push_back((float)v / float(heightmap_cols - 1));
That should now work for any image size.
and what is the indices vector is inserting?
indices.push_back((row - 1) * heightmap_cols col - 1);
indices.push_back((row - 1) * heightmap_cols col);
indices.push_back(row * heightmap_cols col - 1);
indices.push_back(row * heightmap_cols col - 1);
indices.push_back((row - 1) * heightmap_cols col);
indices.push_back(row * heightmap_cols col);
To begin with, we now have a 2D grid of vertices (however that has been flattened into a single array - Points
). I could here write a simple lambda to convert a 2D index pair (U & V) into a 1D index, which may make it a bit more obvious as to what is happening
auto index = [heightmap_cols](int row, int col) {
return row * heightmap_cols col;
};
// (row-1, col) (row, col)
//
// o---------o
// | / |
// | 2 / |
// | / |
// | / |
// | / 1 |
// | / |
// | / |
// o---------o
//
// (row-1, col-1) (row-1, col-1)
// indices for first triangle
indices.push_back(index(row - 1, col - 1));
indices.push_back(index(row - 1, col ));
indices.push_back(index(row , col - 1));
// indices for second triangle
indices.push_back(index(row , col - 1));
indices.push_back(index(row - 1, col ));
indices.push_back(index(row , col ));
This is the function to get silhouette, but I don't get it how does this function work.
It is creating a new array of points, containing only those points whose height is lower than some threshold (in this case, SEALEVEL and the magic number '2').
if (abs(Points[5 * i 2] - SEALEVEL) < 2)
It's probably a badly named function. findAllPointsUnderwater
is probably a better name...