#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 в качестве позиции.