Мне поручено реализовать версию алгоритма сканирования для задания. Эта программа работает путем чтения в списке вершин и цветов из текстового файла. Три вершины и три цвета выталкиваются из очереди за раз, затем обращаются к краям треугольника. До сих пор моя программа прекрасно справлялась. Прежде чем это сделать, нам было поручено задание, которое рисовало прямоугольники, и сразу же после прохождения тестов сразу же стало ясно, что программе необходимо перевернуть координаты y, чтобы изображение было правильно отображено.Реализация алгоритма развертки
В этом проблема. Я нашел несколько алгоритмов для функций заполнения треугольника scanline here, но я заметил, что мне придется их модифицировать, чтобы учесть тот факт, что изображение перевернуто. В сетке компьютерной графики более высокие значения y находятся в нижней части. При организации трех вершин заданного треугольника нормальной задачей является обозначение вершины с наименьшим значением y как вершиной, а вершина с наивысшим значением y в качестве нижней. Я перевернул это, чтобы учесть флип изображения.
Независимо от того, что я делаю, я не могу получить изображение правильно. Он будет работать с этими функциями так, как есть, пока я не переворачиваю значения y при рисовании отдельных пикселей, и вершины сортируются ожидаемым образом, когда более низкие значения y находятся в верхней части. Однако результирующее изображение перевернуто вертикально.
Следующие функции - это в значительной степени полная программа, кроме чертежа строки, которая, как мне кажется, не нуждается в исправлении.
void FrameBuffer::drawTriangle(const Vertex& v0, const Vertex& v1, const Vertex& v2, const Color& c0, const Color& c1, const Color& c2, Functional status) {
//Start by organizing vertices from top to botttom (need to rearrange colors as well)
Vertex vTop, vMid, vLow;
Color cTop, cMid, cLow;
vTop = v0; cTop = c0;
if (v1[Y] > vTop[Y]) {
vMid = vTop; cMid = cTop;
vTop = v1; cTop = c1;
}
else {
vMid = v1; cMid = c1;
}
if (v2[Y] > vTop[Y]) {
vLow = vMid; cLow = cMid;
vMid = vTop; cMid = cTop;
vTop = v2; cTop = c2;
}
else if (v2[Y] > vMid[Y]) {
vLow = vMid; cLow = cMid;
vMid = v2; cMid = c2;
}
else {
vLow = v2; cLow = c2;
}
//Draw the edges of the triangle
drawLine(vTop, vMid, cTop, cMid, status);
drawLine(vTop, vLow, cTop, cLow, status);
drawLine(vMid, vLow, cMid, cLow, status);
//Fill the triangle; first case is flat bottom
if (vMid[Y] == vLow[Y]) {
fillFlatBottom(vTop, vMid, vLow, status);
}
//Second case is flat top
else if (vTop[Y] == vMid[Y]) {
fillFlatTop(vTop, vMid, vLow, status);
}
//General case; triangle can be split into flat bottom above a flat top
else {
Vertex vNew; //This represents the point on the triangle across from the "midpoint"
vNew[Y] = vMid[Y];
vNew[X] = vTop[X] + ((vMid[Y] - vTop[Y])/(vLow[Y] - vTop[Y])) * (vLow[X] - vTop[X]);
vNew[Z] = (vLow[Z] * (vNew[X] - vTop[X]) * (vNew[Y] - vMid[Y]) + vTop[Z] * (vNew[X] - vMid[X]) * (vNew[Y] - vLow[Y]) + vMid[Z] * (vNew[X] - vLow[X]) * (vNew[Y] - vTop[Y]) - vMid[Z] * (vNew[X] - vTop[X]) * (vNew[Y] - vLow[Y]) - vLow[Z] * (vNew[X] - vMid[X]) * (vNew[Y] - vTop[Y]) - vTop[Z] * (vNew[X] - vLow[X]) * (vNew[Y] - vMid[Y]))/((vNew[X] - vTop[X]) * (vNew[Y] - vMid[Y]) + (vNew[X] - vMid[X]) * (vNew[Y] - vLow[Y]) + (vNew[X] - vLow[X]) * (vNew[Y] - vTop[Y]) - (vNew[X] - vTop[X]) * (vNew[Y] - vLow[Y]) - (vNew[X] - vMid[X]) * (vNew[Y] - vTop[Y]) - (vNew[X] - vLow[X]) * (vNew[Y] - vMid[Y]));
fillFlatBottom(vTop, vMid, vNew, status);
fillFlatTop(vMid, vNew, vLow, status);
}
}
//Draw from bottom up (something is happening here that causes errors)
void FrameBuffer::fillFlatTop(const Vertex& v0, const Vertex& v1, const Vertex& v2, Functional status) {
double xSlope1 = -(v2[X] - v0[X])/(v2[Y] - v0[Y]);
double xSlope2 = -(v2[X] - v1[X])/(v2[Y] - v1[Y]);
Vertex curV0 = v2;
Vertex curV1 = v2;
//v0 is the highest point with the highest y value and v2 is the lowest (for this case) with the lowest y value
while (curV0[Y] < v0[Y] && curV1[Y] < v0[Y]) {
Color curC0 = image.get(curV0[X], curV0[Y]);
Color curC1 = image.get(curV1[X], curV1[Y]);
drawLine(curV0, curV1, curC0, curC1, status);
curV0[Y] += 1; curV0[X] -= xSlope1;
curV1[Y] += 1; curV1[X] -= xSlope2;
}
}
//Draw from top down (something is happening here that causes errors)
void FrameBuffer::fillFlatBottom(const Vertex& v0, const Vertex& v1, const Vertex& v2, Functional status) {
double xSlope1 = -(v1[X] - v0[X])/(v1[Y] - v0[Y]);
double xSlope2 = -(v2[X] - v0[X])/(v2[Y] - v0[Y]);
Vertex curV0 = v0;
Vertex curV1 = v0;
//v0 is the highest point with the highest y value and v1 (for this case) is the lowest with the lowest y value
while (curV0[Y] >= v1[Y] && curV1[Y] >= v1[Y]) {
Color curC0 = image.get(curV0[X], curV0[Y]);
Color curC1 = image.get(curV1[X], curV1[Y]);
drawLine(curV0, curV1, curC0, curC1, status);
curV0[Y] -= 1; curV0[X] += xSlope1;
curV1[Y] -= 1; curV1[X] += xSlope2;
}
}
Чтобы обеспечить некоторую перспективу, это результирующее изображение, когда ничего не наполнится: http://imgur.com/a/VOpWJ
Это происходит, когда только fillFlatBottom работает: http://imgur.com/a/nexR9
Это происходит, когда только fillFlatTop работает: http://imgur.com/a/flRCK
Что именно я делаю неправильно? Очевидно, что линейный алгоритм не вызывает этой проблемы. Я либо неправильно вычисляю точку с середины (что является vNew), либо каким-то образом перепутал алгоритмы заполнения.
Что мне нравится в этом посте: лаконично, четко указывается его точки. Затем SO (StackOverflow (& SE: Stack Exchange)) касается вопросов и ответов. Хотя многие вопросные вопросы вряд ли соответствуют базовому требованию «Ответственный вопрос», а заголовок этого сообщения не совсем полезен, возникает явный вопрос: «Что именно я делаю неправильно?». Ваше сообщение не отвечает на это. – greybeard
Да, ты прав. Тем не менее, я опубликовал этот код в качестве рабочего примера. Это на самом деле тот же подход, поэтому плакат может легко обнаружить ошибку, сравнив исходный код с этим. Это не прямой ответ на вопрос: «Что я делаю неправильно?» но это может быть полезно. –