Количество сторон, необходимое для рисования круга в OpenGL

Кто-нибудь знает какой-нибудь алгоритм для вычисления количества сторон, необходимых для аппроксимации круга с помощью многоугольника, если заданы радиус r круга и максимальное отклонение многоугольника от круглости D? Мне действительно нужно найти количество сторон, так как мне нужно нарисовать приближенный круг в OpenGL.

Кроме того, у нас есть разрешение экрана в координатах NDC на пиксель, заданное как P, и, решив D = P/2, мы можем гарантировать, что точность нашего круга не превышает полпикселя.


person Prabal Poudel    schedule 28.08.2013    source источник
comment
Можно просто отправить квад на видеокарту и нарисовать круг во фрагментном шейдере. Это должно быть очень близко к идеальному пикселю.   -  person Dietrich Epp    schedule 29.08.2013


Ответы (3)


То, что вы здесь описываете, фактически является фактором качества, который часто идет рука об руку с оценками ошибок.

Обычный способ справиться с этим — вычислить ошибку для небольшой части окружности круга. Наиболее тривиальным является определение разницы длины дуги среза круга по сравнению с отрезком, соединяющим те же две точки на окружности. Вы можете использовать более эффективные меры, такие как разница в площади, радиусе и т. д., но этот метод должен быть адекватным.

Представьте себе восьмиугольник, описанный идеальной окружностью. В этом случае ошибка представляет собой разницу в длине линии между двумя соседними точками восьмиугольника и длине дуги окружности, соединяющей эти две точки.

введите здесь описание изображения

Длину дуги достаточно легко вычислить: PI * r * theta, где r — радиус, а theta — угол в радианах между двумя точками, при условии, что вы проводите линии от каждой из этих точек к центру круга/многоугольника. Для замкнутого многоугольника с n сторонами угол составляет всего (2*PI/n) радиан. Пусть длина дуги, соответствующая этому значению n, будет равна A, т.е. A=2*PI*r/n.

Длина линии между двумя точками легко вычисляется. Просто разделите свой круг на n равнобедренных треугольников, и каждый из них на два прямоугольных треугольника. Вы знаете, что угол в каждом прямоугольном треугольнике равен theta/2 = (2*PI/n)/2 = (PI/n), а гипотенуза равна r. Таким образом, вы получаете уравнение sin(PI/n)=x/r, где x — это половина длины отрезка, соединяющего две соседние точки на описанном вами многоугольнике. Пусть это значение будет B (то есть: B=2x, значит B=2*r*sin(PI/n)).

Теперь просто вычислите относительную ошибку, E = |A-B| / A (т.е.: |TrueValue-ApproxValue|/|TrueValue|), и вы получите хороший небольшой процент, представленный в десятичном виде, от вашего вектора ошибки. Вы можете использовать приведенные выше уравнения, чтобы установить ограничение на E (то есть: оно не может быть больше некоторого значения, скажем, 1,05), чтобы оно «хорошо выглядело».

Таким образом, вы можете написать функцию, которая вычисляет A, B и E из приведенных выше уравнений, и выполняет цикл по значениям n и прекращает цикл, когда вычисленное значение E меньше вашего порога.

person Cloud    schedule 28.08.2013
comment
в этом случае вы предопределяете n? - person Prabal Poudel; 29.08.2013
comment
Нет. В моем примере мы хотим выполнить обратное решение для n. Выше я описываю функцию, которая принимает коэффициент качества/ошибки, E, и возвращает желаемое количество сторон, n, чтобы обеспечить приближение к кругу на основе желаемого качества. - person Cloud; 29.08.2013
comment
запутался .. скажите, пожалуйста, как вы вычислили B, используя только r и E ... я получил сложное тригонометрическое уравнение, чтобы получить n .. - person Prabal Poudel; 29.08.2013
comment
Вначале вы выбираете E в качестве исходного ограничения, затем вычисляете A. Из уравнения E=|A-B|/|A| можно вычислить B. Тогда вы знаете, что x=B/2. Вы уже знаете r с самого начала, так что вы можете вычислить n из sin(PI/n)=x/r, так как теперь у вас есть все значения, кроме n. Теперь, когда у вас есть n, вы знаете, сколько сегментов вам нужно, чтобы сделать прилично выглядящий круг. Если вы хотите уточнить его, вы можете установить что-то вроде E<D или что-то подобное. - person Cloud; 29.08.2013
comment
Я думаю, что пропустил шаг, так как A и B зависят от угла тета, который зависит от n. - person Cloud; 29.08.2013
comment
очень жаль беспокоить вас .. но для первоначального расчета A мне нужна тета, верно ?? но у меня его нет .. так как я могу рассчитать A из первых рук? если я получу пятерку, то я могу получить и все остальное. Итак, я не уверен, как получить A только из E и r. :( - person Prabal Poudel; 29.08.2013
comment
Я пропустил шаг, и ваше утверждение выше верно. Вы можете рассчитать список значений для E, установив n, а затем остановившись, когда вычисленное значение E станет ниже определенного порога. Обратное решение здесь не работает. Я обновлю свой пост. - person Cloud; 29.08.2013
comment
Ну вот. Я забыл, что к этой процедуре мы подходим с помощью приближения, а не уравнения в замкнутой форме. Изменения выше должны помочь. - person Cloud; 29.08.2013

Я бы сказал, что вам нужно установить количество сторон в зависимости от двух переменных: радиуса и масштабирования (если вы разрешаете масштабирование)

Круг или радиус 20 пикселей могут выглядеть нормально с количеством сторон от 32 до 56, но если вы используете то же количество сторон для радио в 200 пикселей, этого количества сторон будет недостаточно.

numberOfSides = radius * 3

Если вы разрешите увеличение и уменьшение масштаба, вам нужно будет сделать что-то вроде этого

numberOfSides = radiusOfPaintedCircle * 3

Когда вы увеличиваете радиус, radiusOfPaintedCircle будет больше, чем «свойство» рисуемого круга.

person Mauricio Gracia Gutierrez    schedule 28.08.2013
comment
У меня есть радиус r и максимальное отклонение многоугольника от круглости, D. И мне нужно придумать тригнометрическую формулу, которая использует D и r и дает мне необходимое количество сторон, n. - person Prabal Poudel; 29.08.2013
comment
@PrabalPoudel хорошо, может быть, вы можете обновить свой вопрос, чтобы отразить это. - person Mauricio Gracia Gutierrez; 29.08.2013

У меня есть алгоритм рисования круга с использованием фиксированной функции opengl, может быть, это поможет?

Трудно понять, что вы имеете в виду, когда говорите, что хотите «аппроксимировать круг, используя многоугольник».

Вы заметите в моем алгоритме ниже, что я не вычисляю количество линий, необходимых для рисования круга, я просто итерирую между 0 .. 2Pi, каждый раз увеличивая угол на 0,1, рисуя линию с glVertex2f до этой точки на круг, из предыдущей точки.

void Circle::Render()
{   
glLoadIdentity();

glPushMatrix();

    glBegin(GL_LINES);
        glColor3f(_vColour._x, _vColour._y, _vColour._z);
        glVertex3f(_State._position._x, _State._position._y, 0);
        glVertex3f( 
            (_State._position._x + (sinf(_State._angle)*_rRadius)), 
            (_State._position._y + (cosf(_State._angle)*_rRadius)),
            0
        );
    glEnd();

    glTranslatef(_State._position._x, _State._position._y, 0);
    glBegin(GL_LINE_LOOP);
        glColor3f(_vColour._x, _vColour._y, _vColour._z);
        for(float angle = 0.0f; angle < g_k2Pi; angle += 0.1f)
            glVertex2f(sinf(angle)*_rRadius,  cosf(angle)*_rRadius);
    glEnd();                        

glPopMatrix();

}

person fishfood    schedule 28.08.2013