2016-08-17 3 views
0

Я рисую полый эллипс, используя opengl. Я вычисляю вершины в C++-коде, используя стандартную формулу эллипса. В флеш-шейдере я просто назначаю цвет каждому фрагменту. Эллипс, который я вижу на экране, имеет более тонкую ширину линии на более резких кривых по сравнению с тем, что кривая не такая резкая. Итак, вопрос в том, как сделать ширину линии согласованной по всему параметру эллипса? Пожалуйста, смотрите изображение ниже: not worried about jagged edges at this point but it would be great if someone can point out technique to do anti-aliasingширина линии для эллипса не является постоянной

C++ код:

std::vector<float> BCCircleHelper::GetCircleLine(float centerX, float centerY, float radiusX, float radiusY, float lineWidth, int32_t segmentCount) 
{ 
    auto vertexCount = (segmentCount + 1) * 2; 
    auto floatCount = vertexCount * 3; 

    std::vector<float> array(floatCount); 
    const std::vector<float>& data = GetCircleData (segmentCount); 
    float halfWidth = lineWidth * 0.5f; 

    for (int32_t i = 0; i < segmentCount + 1; ++i) 
    { 
     float sin = data [i * 2]; 
     float cos = data [i * 2 + 1]; 

     array [i * 6 + 0] = centerX + sin * (radiusX - halfWidth); 
     array [i * 6 + 1] = centerY + cos * (radiusY - halfWidth); 

     array [i * 6 + 3] = centerX + sin * (radiusX + halfWidth); 
     array [i * 6 + 4] = centerY + cos * (radiusY + halfWidth); 

     array [i * 6 + 2] = 0; 
     array [i * 6 + 5] = 0; 
    } 
    return std::move(array); 
} 

const std::vector<float>& BCCircleHelper::GetCircleData(int32_t segmentCount) 
{ 
    int32_t floatCount = (segmentCount + 1) * 2; 
    float segmentAngle = static_cast<float>(M_PI * 2)/segmentCount; 

    std::vector<float> array(floatCount); 

    for (int32_t i = 0; i < segmentCount + 1; ++i) 
    { 
     array[i * 2 + 0] = sin(segmentAngle * i); 
     array[i * 2 + 1] = cos(segmentAngle * i); 
    } 

    return array; 
} 

Прицеливание это: enter image description here

+0

ОК, так что ... каков ваш вопрос? –

+0

Как сделать линейную ширину согласованной? См. На резких кривых, ширина линии имеет тенденцию быть тоньше. – asad

+0

В каком направлении вы хотите согласовать ширину линии? То есть, как вы хотите измерить эту ширину? –

ответ

3

Проблема, вероятно, что ваши фрагменты в основном отрезки расходящиеся из центра эллипса.

Если вы нарисуете линию, от центра эллипса, через эллипс, который вы нарисовали, в любой точке по периметру вы, вероятно, можете убедиться, что расстояние, покрытое этой красной линией, фактически является шириной, вы после (примерно, так как вы работаете с низким пространственным разрешением, несколько пикселированными). Но поскольку это эллипс, это расстояние не перпендикулярно трассировке пути. И в этом проблема. Это отлично работает для кругов, потому что луч из центра всегда перпендикулярен кругу. Но для этих сплющенных эллипсов это очень наклонно!

Как это исправить? Можете ли вы нарисовать круги в каждой точке эллипса вместо сегментов?

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

Итак, вектор касательной к кривой описывается

c(i) = (a * cos(i), b * sin(i)) 

является

c'(i) = (- a * sin(i), b * cos(i)) 

(обратите внимание, что это не единичный вектор). Перпендикулярна это

c'perp = (b * cos(i), a * sin(i)) 

Вы должны быть в состоянии убедить себя, что это правда, вычисляя их скалярное произведение.

Позволяет рассчитать величину c'perp, и назвать его k сейчас:

k = sqrt(b * b * cos(i) * cos(i) + a * a * sin(i) * sin(i)) 

Так мы выходим в точку на эллипсе (с (I)), и мы хотим сделать segement что это перпендикуляр к кривой - это означает, что мы хотим добавить масштабированную версию c'perp. Масштабирование должно делить на величину (k), а затем умножить на половину ширины вашей линии. Таким образом, двумя конечными точками являются:

P1 = c(i) + halfWidth * c'perp/k 
P2 = c(i) - halfWidth * c'perp/k 

Я не проверял это, но я уверен, что он близко.Вот геометрия вы работаете с:

enter image description here

- Edit:

Так значения для P1 и P2, что я даю выше являются конечными точками линии-сегмента, который, перпендикулярно эллипс. Если вы действительно хотите продолжить с изменением значений radiusX и radiusY так, как вы делали, вы можете это сделать. Вам просто нужно выяснить, что длина «не w» находится под каждым углом, и использовать половину этого значения вместо halfWidth в radiusX +/- halfWidth и radiusY +/- halfwidth. Я оставляю эту часть геометрии в качестве упражнения для читателя.

+0

Спасибо вам большое !!!!!. Еще один вопрос? Есть ли способ написать общее уравнение для внутреннего эллипса на основе внешнего эллипса, так что тот же результат может быть достигнут – asad

+0

hmmm, я не уверен, что внутренние и внешние кривые на самом деле являются эллипсами. Поэтому я считаю, что описание выше для P1 и P2. Вы видите, что вы сделали, заполнили пробел между двумя эллипсами - вы изменили основные и второстепенные топоры, чтобы достичь этого. Это эллипсы с этими основными и второстепенными осями. И это заставляет меня быть уверенным, что две кривые, которые вы ищете, на самом деле не на самом деле эллипсы! – Arunas

+0

на самом деле, вы можете обнаружить, что если вы производите некоторую алгебру с k (длина перпендикуляра), то вы получите гораздо более компактную закрытую форму. – Arunas

Смежные вопросы