OpenGL impostor -phere: проблема при расчете значения глубины - PullRequest
0 голосов
/ 06 декабря 2018

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

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

IMG

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

Это вершинные и фрагментные шейдеры для сферы-самозванца.

вершинный шейдер :

#version 450 core

uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;

out vec2 coords;

void main()
{
    switch (gl_VertexID)
    {
    case 0:
        coords = vec2(-1.0f, -1.0f);
        break;
    case 1:
        coords = vec2(-1.0f, +1.0f);
        break;
    case 2:
        coords = vec2(+1.0f, -1.0f);
        break;
    case 3:
        coords = vec2(+1.0f, +1.0f);
        break;
    }

    // right & up axes camera space
    vec3 right = vec3(view[0][0], view[1][0], view[2][0]);
    vec3 up = vec3(view[0][1], view[1][1], view[2][1]);

    vec3 center = vec3(0.0f);
    float radius = 1.0f;

    // vertex position
    vec3 position = radius * vec3(coords, 0.0f);
    position = right * position.x + up * position.y;

    mat4 MVP = projection * view * model;
    gl_Position = MVP * vec4(center + position, 1.0f);
}

фрагментный шейдер :

#version 450 core

uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;

in vec2 coords;
out vec4 pixel;

void main()
{
    float d = dot(coords, coords);

    if (d > 1.0f)
    {
        discard;
    }

    float z = sqrt(1.0f - d);

    vec3 normal = vec3(coords, z);
    normal = mat3(transpose((view * model))) * normal;

    vec3 center = vec3(0.0f);
    float radius = 1.0f;

    vec3 position = center + radius * normal;

    mat4 MVP = projection * view * model;

    // gl_DepthRange.diff value is the far value minus the near value

    vec4 clipPos = MVP * vec4(position, 1.0f);
    float ndcDepth = clipPos.z / clipPos.w;
    gl_FragDepth = ((gl_DepthRange.diff * ndcDepth) + gl_DepthRange.near + gl_DepthRange.far) * 0.5f;

    pixel = vec4((normal + 1.0f) * 0.5f, 1.0f);
}

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

Матрица модели, которую я передаю шейдерам, является единичной матрицей, поэтому она не влияет на операции.

Большое спасибо за вашу помощь!!

Ответы [ 2 ]

0 голосов
/ 07 декабря 2018

Хорошо, я думаю, что наконец-то решил проблему.

Я использовал трассировку лучей в соответствии с предложением @NicolBolas после урока, и это результат.

enter image description here

Это вершинные и фрагментные шейдеры для сферы-самозванца.

вершинный шейдер :

#version 330

out vec2 mapping;

uniform mat4 view;
uniform mat4 cameraToClipMatrix;

const float sphereRadius = 1.0f;
const vec3 worldSpherePos = vec3(0.0f);

const float g_boxCorrection = 1.5;

void main()
{
    vec2 offset;
    switch(gl_VertexID)
    {
    case 0:
        //Bottom-left
        mapping = vec2(-1.0, -1.0) * g_boxCorrection;
        offset = vec2(-sphereRadius, -sphereRadius);
        break;
    case 1:
        //Top-left
        mapping = vec2(-1.0, 1.0) * g_boxCorrection;
        offset = vec2(-sphereRadius, sphereRadius);
        break;
    case 2:
        //Bottom-right
        mapping = vec2(1.0, -1.0) * g_boxCorrection;
        offset = vec2(sphereRadius, -sphereRadius);
        break;
    case 3:
        //Top-right
        mapping = vec2(1.0, 1.0) * g_boxCorrection;
        offset = vec2(sphereRadius, sphereRadius);
        break;
    }

    vec3 cameraSpherePos = vec3(view * vec4(worldSpherePos, 1.0));

    vec4 cameraCornerPos = vec4(cameraSpherePos, 1.0);
    cameraCornerPos.xy += offset * g_boxCorrection;

    gl_Position = cameraToClipMatrix * cameraCornerPos;
}

фрагментный шейдер :

#version 330

in vec2 mapping;

out vec4 outputColor;

uniform mat4 view;
uniform mat4 cameraToClipMatrix;

const float sphereRadius = 1.0f;
const vec3 worldSpherePos = vec3(0.0f);

uniform vec3 eye;

void Impostor(out vec3 cameraPos, out vec3 cameraNormal)
{
    vec3 cameraSpherePos = vec3(view * vec4(worldSpherePos, 1.0));

    vec3 cameraPlanePos = vec3(mapping * sphereRadius, 0.0) + cameraSpherePos;
    vec3 rayDirection = normalize(cameraPlanePos);

    float B = 2.0 * dot(rayDirection, -cameraSpherePos);
    float C = dot(cameraSpherePos, cameraSpherePos) - (sphereRadius * sphereRadius);

    float det = (B * B) - (4 * C);
    if(det < 0.0)
        discard;

    float sqrtDet = sqrt(det);
    float posT = (-B + sqrtDet)/2;
    float negT = (-B - sqrtDet)/2;

    float intersectT = min(posT, negT);
    cameraPos = rayDirection * intersectT;
    cameraNormal = normalize(cameraPos - cameraSpherePos);
}

void main()
{
    vec3 cameraPos;
    vec3 cameraNormal;

    Impostor(cameraPos, cameraNormal);

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

    cameraNormal = mat3(transpose(view)) * cameraNormal;

    outputColor = vec4((cameraNormal + 1.0f) * 0.5f, 1.0f);
}

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

Я хотел бы задать вам несколько вопросов.

  • Как видите, я по-прежнему умножаю нормаль каждого фрагмента на транспонирование матрицы вида.Это правильно?Таким образом, я точно увижу сферу, «ориентированную» правильно, когда я перемещаю камеру вокруг нее?

  • О корректировке размеров ящиков, как я могу быть уверенчто увеличение размера квадрата на 50% работает в любой ситуации?В учебном пособии упоминается, что для определения точных размеров квадратора необходимо учитывать область просмотра и матрицу перспективы.Знаете ли вы, как можно выполнить этот расчет?

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

enter image description here

  • Теперь мне нужно отрендерить десятки илисотни тысяч сфер-самозванцев в одной сцене.Мне интересно, не слишком ли дорогой расчет трассировки лучей для стольких сфер.Также я добавлю вычислительную стоимость освещения.Я знаю, что есть другая техника, называемая лучевым маршированием, которая должна быть дешевле, но в настоящее время я не знаю, подходит ли она в моем случае.

Большое спасибо за вашу помощь!:)

0 голосов
/ 06 декабря 2018

Ваши вычисления глубины в порядке.Проблема, с которой вы столкнулись, по сути та же самая, что описана в самом уроке, из которого вы взяли ваши глубинные вычисления.Это другое проявление этой проблемы, но все они происходят из одного и того же места: ваши вычисления position неверны относительно реальности.Так что плохие значения подаются на вычисление глубины;неудивительно, что вы не получаете правильный результат.

Это преувеличенное 2D-представление вашей основной проблемы:

A picture of a circle impostor, with a close-up viewer

Мы на Вью, смотрим на Точку.Согласно вашему коду самозванца, мы вычислим положение для точки, по существу проецируя ее вперед перпендикулярно плоскости, пока она не достигнет сферы.Это вычисление дает точку самозванца.

Однако, как вы можете видеть, это не , что показывает реальность.Если мы рисуем линию от точки к точке зрения (которая представляет то, что мы должны видеть от точки зрения в этом направлении), первая позиция в сфере, которую мы видим, - это реальная.И это очень далеко от Impostor.

Поскольку фундаментальная проблема заключается в том, что ваше вычисление положения самозванца неверно, единственный способ исправить это - использовать правильное вычисление самозванца.И правильный способ сделать это (так или иначе) через трассировку лучей сферы из View.Что является тем, что делает учебник .

...