Расчет нормалей для результатов освещения модели в модели больше не рендерит - PullRequest
0 голосов
/ 07 ноября 2018

Я работаю над простым движком рендеринга в Java, который может рендерить файлы OBJ на экран. В настоящее время я работаю над системой освещения, которая используется для освещения моделей, присутствующих на экране. Перед внедрением системы освещения я смог легко загрузить модели на экран:

enter image description here

однако, когда я добавляю свет на экран, модель больше не появляется. Я использую следующий шейдер для визуализации света:

VertexShader:

#version 150

in vec3 position;
in vec2 textureCoordinates;
in vec3 normals;

out vec2 passTextureCoordinates;
out vec3 surfaceNormal;
out vec3 toLightVector;

uniform mat4 transformationMatrixTextured;
uniform mat4 projectionMatrixTextured;
uniform mat4 viewMatrixTextured;
uniform vec3 lightLocation;

void main(void){
    vec4 worldPosition = transformationMatrixTextured * vec4(position,1.0);
    gl_Position = projectionMatrixTextured * viewMatrixTextured * worldPosition;
    passTextureCoordinates = textureCoordinates;

    surfaceNormal =  (transformationMatrixTextured * vec4(normals,0.0)).xyz;
    toLightVector =  lightLocation - worldPosition.xyz;
}

FragmentShader:

#version 150

in vec2 passTextureCoordinates;
in vec3 surfaceNormal;
in vec3 toLightVector;

out vec4 out_Color;

uniform sampler2D textureSampler;
uniform vec3 lightColor;

void main(void){

    vec3 unitNormal = normalize(surfaceNormal);
    vec3 unitLightVector = normalize(toLightVector);

    float nDot1 = dot(unitNormal, unitLightVector);
    float brightness = max(nDot1, 0.0);
    vec3 diffuse = brightness * lightColor;

    out_Color = vec4(diffuse, 1.0) * texture(textureSampler,passTextureCoordinates);

}

Я использую учебную серию от ThinMatrix , чтобы помочь мне в создании этой программы. Однако, одно большое отличие состоит в том, что я также хочу иметь возможность загружать программно созданные модели, в отличие от использования только моделей, загруженных OBJLoader. Из-за этого мне пришлось создать способ вычисления нормалей по массиву вершин и массиву индексов.

Мой подход к этой проблеме был следующим:

/**
 * Sum.
 *
 * @param arg1 the arg 1
 * @param arg2 the arg 2
 * @return the vector 3 f
 */
public static Vector3f sum(Vector3f arg1, Vector3f arg2) {
    return new Vector3f(arg1.x + arg2.x, arg1.y + arg2.y, arg1.z + arg2.z);
}

/**
 * Subtract.
 *
 * @param arg1 the arg 1
 * @param arg2 the arg 2
 * @return the vector 3 f
 */
public static Vector3f subtract(Vector3f arg1, Vector3f arg2) {
    return new Vector3f(arg1.x - arg2.x, arg1.y - arg2.y, arg1.z - arg2.z);
}

/**
 * Cross product.
 *
 * @param arg1 the arg 1
 * @param arg2 the arg 2
 * @return the vector 3 f
 */
public static Vector3f crossProduct(Vector3f arg1, Vector3f arg2) {
    return new Vector3f(arg1.y * arg2.z - arg2.y * arg1.z, arg2.x * arg1.z - arg1.x * arg2.z, arg1.x * arg2.y - arg2.x * arg1.y);
}

/**
 * Gets the normals.
 *
 * @param vertices the vertices
 * @param indexes the indexes
 * @return the normals
 */
public static float[] getNormals(float[] vertices, int[] indexes) {
    vertices = convertToIndexless(vertices, indexes);
    Vector3f tmp;
    float[] tmpArray = new float[vertices.length / 3];
    int tmpArrayCounter = 0;
    for(int i = 0; i < vertices.length; i+=9) {
        Vector3f edge1 = subtract(new Vector3f(vertices[i], vertices[i + 1], vertices[i + 2]) , new Vector3f(vertices[i + 3], vertices[i + 4], vertices[i + 5]));
        Vector3f edge2 = subtract(new Vector3f(vertices[i], vertices[i + 1], vertices[i + 2]) , new Vector3f(vertices[i + 6], vertices[i + 7], vertices[i + 8]));

        tmp = crossProduct(edge1, edge2);
        tmpArray[tmpArrayCounter++] = tmp.getX();
        tmpArray[tmpArrayCounter++] = tmp.getY();
        tmpArray[tmpArrayCounter++] = tmp.getZ();
    }
    return tmpArray;
}

/**
 * Convert to indexless.
 *
 * @param vertices the vertices
 * @param indexes the indexes
 * @return the float[]
 */
private static float[] convertToIndexless(float[] vertices, int[] indexes) {
    float[] tmpArray = new float[indexes.length * 3];
    for(int i = 0; i < indexes.length; i++) {
        tmpArray[i * 3]     = vertices[indexes[i] * 3];
        tmpArray[i * 3 + 1] = vertices[indexes[i] * 3 + 1];
        tmpArray[i * 3 + 2] = vertices[indexes[i] * 3 + 2];
    }
    return tmpArray;
}

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

1 Ответ

0 голосов
/ 16 ноября 2018

Длинное описание, чтобы узнать корневую проблему

Честно говоря, я не понимаю, что означает the model does no longer show up. Поэтому я собираюсь опубликовать несколько советов, как вы можете узнать, что происходит.

  • Является ли представленная модель полностью черной?

    • Может быть несколько источников проблем, которые необходимо проверить:

      • Включите какой-нибудь цвет фона, например синий, чтобы увидеть, каков будет результат.
        • Модель невидима, поэтому все синее? Нормалы модели неверны. Вы можете включить, чтобы сделать обе стороны, ключевое слово face culling, чтобы узнать. Если он рендерится с рендерингом на обратной стороне, то нормали модели - это проблема
        • Модель видима, но модель отображается черным, а фон - синим?
          • неправильное направление света (очень вероятно)
          • Я предлагаю изменить шейдер так, чтобы всегда было минимальное количество света, так называемое окружающее освещение. Тогда каждый объект получает минимальную молнию, даже несмотря на плохой угол относительно источника света, такой как intensity = max(dot(n, l), ambience); в вершинном шейдере с ambience в качестве параметра и n нормализованной нормалью объекта и l нормализованное направление света. В фрагментном шейдере я использовал gl_FragColor = vec4(intensity*tc.r,intensity*tc.g,intensity*tc.b,tc.a);, где tc - координата текстуры vec4. Таким образом, у объекта всегда есть свет
          • или какая-то ошибка в коде шейдера (с первого взгляда не удалось обнаружить проблему, но кто знает?) Ну, для этого я использовал точечное произведение модели, перпендикулярной направлению света, в вашем коде, кажется, есть крест продукт.
      • Текстура не используется / не принята / не назначена прямо на модель, или вектор возвращает только одно местоположение пикселя, которое является черным
    • Есть ли ошибка в коде шейдера? Ошибка компиляции, которая зарегистрирована как исключение?

      • исправить это;)

Полагаю, проблема в том, что я использую перекрестное произведение и неправильное направление света (у меня в начале была такая же проблема в моей модели)

Редактировать Еще один комментарий к точечному продукту: точечный продукт - это то, что вам нужно для определения интенсивности. Геометрическое определение этого dot(a,b)=length(a)*length(b)*cos(alpha), где alpha - угол между a и b.

  • Если нормаль модели совпадает с направлением света, вам нужна полная интенсивность.

  • Если нормаль модели находится в ортогональном направлении (90 градусов) в качестве направления света, тогда вы хотите 0 интенсивности (или интенсивности окружения)

  • Если нормаль модели составляет 60 градусов в направлении направления света, то вам нужна половина интенсивности (или интенсивности окружения)

и т.д.

Редактировать 2 - поскольку скалярное произведение может иметь отрицательные результаты, теперь max(dot(a,b),0) отрежет это (для противоположного направления). Для быстрой обстановки вы можете изменить это на max(dot(a,b),0.3)

Резюме:

  • Используйте точечное произведение для расчета интенсивности.

  • Используйте рассеянный свет для освещения, даже если угол относительно источника света плохой.

...