Затухание размера спрайтов в точках с помощью современного OpenGL
Я пытаюсь визуализировать некоторые частицы с OpenGL 3+, используя точечные спрайты. Я только что понял, что у меня есть серьезная проблема с очками. Они увеличиваются в размере автоматически в зависимости от расстояния до камеры. В результате чего следующее:
Рядом с эмиттером частиц:
А когда далеко, все выглядит расплывчатым и раздутым
В более старых версиях кажется, что можно настроить шкалы размеров точек с помощью 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 применяется сначала к позиции частицы, а затем вычисляется расстояние до этой позиции. Потому что, если вы применяете преобразования к объекту системы частиц, ваши частицы лежат в координатах объекта, которые не равны глобальным координатам. Поэтому я вычисляю расстояние в координатах вида (где камера всегда в исходной точке).