Минимальный размер визуализируемого объекта с использованием GL_LINES в iOS Open GL ES - PullRequest
1 голос
/ 27 февраля 2012

Я только что закончил первую версию своего приложения для iOS, Corebox , и сейчас работаю над некоторыми новыми функциями.

Одна из новых функций - это «небольшая» настройка рендеринга OpenGL, чтобы заставить некоторые объекты никогда не рисоваться меньше минимального размера. Все объекты, нуждающиеся в этой обработке, представляют собой простые 2-точечные линии, нарисованные с помощью GL_LINES.

Этот аннотированный скриншот объясняет, что мне нужно. Не обращайте внимания на серые линии, единственные объекты, которые меня интересуют, это более широкие желтые линии.

Corebox OpenGL scene

Я очень много гуглил, и мне кажется, что мне нужно изменить геометрию линий, используя вершинный шейдер. Я довольно новичок в GLSL, и большинство примеров шейдеров, которые я могу найти, касаются применения освещения и других эффектов, например: GLSL Heroku Editor и KicksJS редактор шейдеров .

Мой текущий вершинный шейдер чрезвычайно прост:

// GL_LINES vertex shader
uniform mat4 Projection;
uniform mat4 Modelview;

attribute vec4 Position;
attribute vec4 SourceColor;

varying vec4 DestinationColor;

void main(void) {
    DestinationColor = SourceColor;
    gl_Position = Projection * Modelview * Position;
}

Как и мой фрагментный шейдер:

// GL_LINES fragment shader
varying lowp vec4 DestinationColor;

void main(void) {
    gl_FragColor = DestinationColor;
}

Мое предположение относительно того, что требуется:

  • Определить расстояние между зрителем (положение камеры) и объектом
  • Определите, насколько велик объект на экране, исходя из его размера и расстояния до камеры
  • Если объект будет слишком маленьким, отрегулируйте его вершины так, чтобы он стал достаточно большим, чтобы его можно было легко увидеть на экране.

Предостережения и другие примечания:

  1. Но если вы уменьшите масштаб, не приведет ли это к тому, что модель будет просто оранжевым шариком на экране? Да, это именно тот эффект, который мне нужен.

Редактировать: вот окончательная рабочая версия реализации предложений от mifortin

uniform mat4 Projection;
uniform mat4 Modelview;
uniform float MinimumHeight;

attribute vec4 Position;
attribute vec4 ObjectCenter;
attribute vec4 SourceColor;

varying vec4 DestinationColor;

void main(void) {
    // screen-space position of this vertex
    vec4 screenPosition = Projection * Modelview * Position;
    // screen-space mid-point of the object this vertex belongs to
    vec4 screenObjectCenter   = Projection * Modelview * ObjectCenter;

    // Z should be 0 by this time and the projective transform in w.
    // scale so w = 1  (these two should be in screen-space)
    vec2 newScreenPosition = screenPosition.xy / screenPosition.w;
    vec2 newObjectCenter   = screenObjectCenter.xy / screenObjectCenter.w;

    float d = distance(newScreenPosition, newObjectCenter);

    if (d < MinimumHeight && d > 0.0) {
        // Direction of this object, this really only makes sense in the context
        // of a line (eg: GL_LINES)
        vec2 towards = normalize(newScreenPosition - newObjectCenter);

        // Shift the center point then adjust the vertex position accordingly
        // Basically this converts: *--x--* into *--------x--------*
        newObjectCenter = newObjectCenter + towards * MinimumHeight;
        screenPosition.xy = newObjectCenter.xy * screenPosition.w;
    }

    gl_Position = screenPosition;
    DestinationColor = SourceColor;
}

1 Ответ

2 голосов
/ 28 февраля 2012

Обратите внимание, что я не тестировал код, но он должен проиллюстрировать решение.

Если вы хотите использовать шейдеры, добавьте еще одну унифицированную vec4, которая является центральной позицией вашей линии.Затем вы можете сделать что-то похожее (центр примечания можно предварительно вычислить на процессоре один раз):

uniform float MIN;   //Minimum size of blob on-screen
uniform vec4 center; //Center of the line / blob
...
vec4 screenPos = Projection * Modelview * Position;
vec4 center = Projection * Modelview * Position;

//Z should be 0 by this time and the projective transform in w.
//scale so w = 1  (these two should be in screen-space)
vec2 nScreenPos = screenPos.xy / screenPos.w;
vec2 nCenter = center.xy / center.w;

float d = distance(nScreenPos, nCenter);
if (d < MIN && d > 0)
{
    vec2 towards = normalize(nScreenPos - nCenter);
    nCenter = nCenter + towards * MIN;

    screenPos.xy = nCenter.xy * screenPos.w;
}

gl_Position = screenPos;

Найдите, где на экране будет нарисована вершина, затем, если необходимо, от центра большого объекта вытяните ее.чтобы обеспечить минимальный размер.

Этот пример для круглых объектов.Для углов вы можете сделать MIN атрибутом, чтобы расстояние от центра варьировалось для каждой вершины.

Если вы просто хотите что-то более коробчатое, убедитесь, что минимальное расстояние от x икоординаты y отдельно.

В ЦП вы можете вычислить координаты в пространстве экрана и соответственно масштабироваться перед отправкой в ​​графический процессор.

...