Затухание размера спрайтов в точках с помощью современного OpenGL

Я пытаюсь визуализировать некоторые частицы с OpenGL 3+, используя точечные спрайты. Я только что понял, что у меня есть серьезная проблема с очками. Они увеличиваются в размере автоматически в зависимости от расстояния до камеры. В результате чего следующее:

Рядом с эмиттером частиц:

colse

А когда далеко, все выглядит расплывчатым и раздутым

далеко

В более старых версиях кажется, что можно настроить шкалы размеров точек с помощью glPointParameter, Функция все еще доступна в новом 3+ OpenGL, но поддерживает только два параметра. GL_POINT_FADE_THRESHOLD_SIZE казалось, что мне нужно, но я попробовал безрезультатно. Я также использую glEnable(GL_PROGRAM_POINT_SIZE);

Другим способом, которым я мог избежать этого автоматического масштабирования точек, основанных на расстоянии камеры? Я бы предпочел не переходить на код, чтобы использовать стандартные рекламные щиты из треугольников.

Не уверен, что актуально в данный момент, но я использую вершинный шейдер:

layout(location = 0) in vec4 a_position_size; // Point size in w coord
layout(location = 1) in vec4 a_color;         // RGBA color modulated with texture

layout(location = 0) out vec4 v_color;

uniform mat4 u_MVPMatrix;

void main()
{
    gl_Position  = u_MVPMatrix * vec4(a_position_size.xyz, 1.0);
    gl_PointSize = a_position_size.w;
    v_color      = a_color;
}

2 ответа

Решение

Так что получается, что моя проблема была из-за моего недопонимания gl_PointSize, Как было отмечено в комментариях и четко указано в документации, gl_PointSize содержит размер растеризованных точек в пикселях. Следовательно, точечные спрайты выглядят больше, когда мы удаляемся от них, но не потому, что они масштабируются, а потому, что они все еще занимают то же пространство экрана, в то время как остальная часть 3D-сцены уменьшается в соответствии с перспективной проекцией.

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

uniform mat4 u_MVPMatrix;
uniform vec3 u_cameraPos;

// Constants (tweakable):
const float minPointScale = 0.1;
const float maxPointScale = 0.7;
const float maxDistance   = 100.0;

void main()
{
    // Calculate point scale based on distance from the viewer
    // to compensate for the fact that gl_PointSize is the point
    // size in rasterized points / pixels.
    float cameraDist = distance(a_position_size.xyz, u_cameraPos);
    float pointScale = 1.0 - (cameraDist / maxDistance);
    pointScale = max(pointScale, minPointScale);
    pointScale = min(pointScale, maxPointScale);

    // Set GL globals and forward the color:
    gl_Position  = u_MVPMatrix * vec4(a_position_size.xyz, 1.0);
    gl_PointSize = a_position_size.w * pointScale;
    v_color      = a_color;
}

Была такая же проблема при использовании GLSL с three.js. Решил это, основываясь на ответе Гламперта, но прежде всего для Three.js необходимо использовать определенные предопределенные имена переменных:

uniform vec4 origin;

void main() {
    vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );
    float cameraDist = distance( mvPosition, origin );
    gl_PointSize = 200.0 / cameraDist;
    gl_Position = projectionMatrix * mvPosition;
}

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

Другие вопросы по тегам