Индикатор точки OpenGL неправильно преобразован

#java #opengl #camera #glsl #lighting

#java #opengl #камера #glsl #Освещение

Вопрос:

Я работаю над добавлением базового точечного освещения в мой игровой движок на основе LWJGL. Я использую индикаторы с фиксированной функцией OpenGL для определения положения и цвета, но использую шейдеры для выполнения фактических вычислений освещения. Моя проблема где-то в преобразовании из мирового пространства в координаты глазного пространства. Моя цель состоит в том, чтобы индикатор находился в фиксированном положении относительно мира. Я знаю, что когда вы устанавливаете положение источника света, он преобразуется стеком матрицы OpenGL так же, как геометрия. Однако, когда я перемещаю камеру, освещение меняется. Функция clearRenderer вызывается в начале фазы рендеринга каждого кадра (матрица GL_PROJECTION уже настроена):

 public static void clearRenderer(CameraViewpoint viewpoint) {
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    setupCamera3D(viewpoint);
    Light.drawLights();
}

public static void setupCamera3D(CameraViewpoint viewpoint) {
    Angles a = viewpoint.cameraAngle();
    Vector3 pos = viewpoint.cameraPosition();

    rotateZ(-a.roll);
    rotateX(-a.pitch);
    rotateY(-a.yaw);

    translate(pos.negate());
}
  

Вот drawLights функция в Light классе, которая вызывается в приведенном выше коде:

 public static void drawLights() {
    for (int i = 0; i < numLights; i  ) {
        lights[i].drawLight();
    }
}

public void drawLight() {
    FloatBuffer buff = BufferUtils.createFloatBuffer(4);
    pos.store(buff); // pos is the position of the light in world-space
    buff.put(1.0f);
    buff.flip();
    glLight(GL_LIGHT0   index, GL_POSITION, buff);
}
  

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

 uniform float time;

varying vec3 normal;

void main() {
    gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
    normal = (gl_NormalMatrix * gl_Normal);
    gl_TexCoord[0] = gl_MultiTexCoord0;
}
  

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

 uniform float time;

uniform vec3 m_ambient;
uniform vec3 m_diffuse;
uniform vec3 m_specular;

uniform sampler2D tex;

varying vec3 normal;

void main() {

    vec4 lightPos = gl_LightSource[0].position;

    vec4 color = texture2D(tex, gl_TexCoord[0].st);
    vec3 light = m_ambient;
    float f = dot(normalize((lightPos - gl_FragCoord).xyz), normalize(normal));

    f = clamp(f, 0.0, 1.0);

    light  = m_diffuse * f;
    color.a = 1.0;
    gl_FragColor = color * vec4(light, 1.0);
}
  

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

Ответ №1:

Хорошо, исправлено. Я делал несколько вещей неправильно. В основном, gl_FragCoord фактически ссылается на положение пикселя на экране, что не совпадает с пространством для глаз. Итак, я просто создал единую переменную для хранения координаты вершины в пространстве для глаз. Кроме того, позиции света и нормали не преобразуются матрицей GL_PROJECTION, поэтому я должен был убедиться, что не преобразовал этим переменную положения.

Кроме того, чтобы установить положение источника света, проще просто преобразовать матрицу GL_MODELVIEW по позиции и использовать буфер, содержащий 0, 0, 0, 1 в качестве позиции.