Как сделать так, чтобы GL_POINTS перекрывались, чтобы они выглядели как сферы?

Я пытаюсь создать игру в стиле вокселей и хочу использовать GL_POINTS для имитации сферических вокселей.

Я стремлюсь, чтобы они выглядели как 3D-сферы без необходимости рендеринга реальной сферы со многими вершинами.

Однако, когда я создал массу GL_POINTS, они перекрываются таким образом, что становится очевидным, что это спрайты с плоскими кругами.

Вот пример: пример моего изображения с перекрытием gl_points, показывающим круговой спрайт:

img

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

В качестве примера того, чего я хотел бы достичь, вот изображение, показывающее Star Defenders 3D от Эрика Гурта, в котором он использовал сферические точки в качестве вокселей в Javascript для своих уровней:

Пример изображения, показывающего точки, похожие на сферы:

img

Как видите, в местах наложения точек они скрывают части друг друга, создавая иллюзию того, что они представляют собой 3D-сферы, а не круглые спрайты.

Есть ли способ воспроизвести это в openGL? Я использую OpenGL 3.3.0.


person rabbet    schedule 26.04.2020    source источник
comment
Можно установить глубину (gl_FragDepth) зависит от расстояния до центра сферы в фрагментном шейдере   -  person Rabbid76    schedule 26.04.2020
comment
@Rabbid76 Спасибо за ваш комментарий! Я даже не знал, что такое gl_fragdepth. Я провел некоторое исследование, все еще пытаясь понять, как заставить это работать...   -  person rabbet    schedule 26.04.2020
comment
см. Как я могу создать градиентную сферу на glsl? просто установите glPointSize(), чтобы покрыть вашу сферу с фактическим масштабированием/поле зрения и в шейдере вычислить фрагменты поверхности сферы... Другой альтернативой glPointSize является геометрический шейдер, испускающий треугольники из точек... не забудьте обновить глубину фрагмента, как предложил Rabbid76   -  person Spektre    schedule 27.04.2020
comment
@Spektre спасибо за ваш ответ, я все еще учусь и стараюсь изо всех сил, чтобы заставить его работать   -  person rabbet    schedule 28.04.2020
comment
аналогичный вопрос задан здесь: stackoverflow.com/questions/53650693/ . Он разобрался в самом низу, правда, все это было сделано без использования GL_POINTS, а вместо него использовался квадр с двумя треугольниками. Мне трудно заставить это работать с GL_POINTS :(   -  person rabbet    schedule 28.04.2020
comment
@rabbet IIRC glPointSize не безграничен, поэтому, если ваши сферы слишком велики, они не будут полностью покрыты точечным прямоугольником, поэтому я предложил геометрическому шейдеру испускать треугольники, если glPointSize недостаточно. Однако новый GLSL не распознает примитив QUAD в геометрическом шейдере, поэтому он должен быть треугольником (либо 1, либо 2).   -  person Spektre    schedule 28.04.2020
comment
@Spektre, это мой код для вычисления glpointsize, он в моем шейдере gl_PointSize = viewPortSize.y * projectionMatrix[1][1] * pointRadius / gl_Position.w;   -  person rabbet    schedule 28.04.2020
comment
@rabbet На данный момент я игнорирую вычисление размера и использую жестко запрограммированный размер ... поскольку я борюсь с более серьезной проблемой, поскольку трансформированные координаты подозрительны для примитива GL_POINT, нужно подумать о преобразовании из экранного пространства в мировые координаты ... возможно, обратная проекция raycasting . Таким образом, кажется, что геометрический шадр был бы более простым подходом.   -  person Spektre    schedule 28.04.2020
comment
@Spektre это позволяет вам управлять gl_PointSize в шейдерной программе: glEnable(GL_VERTEX_PROGRAM_POINT_SIZE); Также разве размер точки gl не контролирует только ширину 2d-спрайта в пикселях? Я не думаю, что это имеет какое-либо отношение к глубине..   -  person rabbet    schedule 28.04.2020
comment
не знал, что ... Я ударяюсь о стену ... шейдер gl_FragCoord внутри фрагмента неверен для больших точек ... поэтому я не могу пересчитать положение поверхности. Либо я делаю что-то глупое, но, скорее всего, это ошибка драйвера :(   -  person Spektre    schedule 28.04.2020
comment
@rabbet Держу пари, что точка просто копируется, а не реинтерполируется. Однако фрагментный шейдер вызывается несколько раз, есть некоторая степень изменения, но он в тысячи раз меньше, чем должен быть :( поэтому необработанный GL_POINTS не годится. Единственное, что осталось, это испускать описанные примитивы в геометрии... или использовать что-то вроде этого : трассировщик вокселей GLSL   -  person Spektre    schedule 28.04.2020


Ответы (1)


Наконец-то я реализовал способ сделать точки похожими на сферы, изменив gl_FragDepth.

Это код из моего фрагментного шейдера, который превращает квадратную точку gl_point в сферу. (без освещения)

void makeSphere()
{
    //clamps fragments to circle shape. 
    vec2 mapping = gl_PointCoord * 2.0F - 1.0F;
    float d = dot(mapping, mapping);

    if (d >= 1.0F)
    {//discard if the vectors length is more than 0.5
        discard;
    }
    float z = sqrt(1.0F - d);
    vec3 normal = vec3(mapping, z);
    normal = mat3(transpose(viewMatrix)) * normal;
    vec3 cameraPos = vec3(worldPos) + rad * normal;


    ////Set the depth based on the new cameraPos.
    vec4 clipPos = projectionMatrix * viewMatrix * vec4(cameraPos, 1.0);
    float ndcDepth = clipPos.z / clipPos.w;
    gl_FragDepth = ((gl_DepthRange.diff * ndcDepth) + gl_DepthRange.near + gl_DepthRange.far) / 2.0;

    //calc ambient occlusion for circle
    if (bool(fAoc))
        ambientOcclusion = sqrt(1.0F - d * 0.5F);
}
person rabbet    schedule 26.10.2020