Нормальное преобразование OpenGL в шейдерах

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

Вот мой оригинальный вершинный шейдер:

uniform vec3 lightDir;
varying vec3 normal;

void main()
{       
    normal = gl_NormalMatrix*gl_Normal;
    gl_Position = ftransform();
}

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

varying vec3 normal;

void main(){
    vec3 color = vec3(1,1,1);
    vec3 lightDir = vec3(1,1,0);
    float inten = 1;
    color = color*dot(normal, lightDir)*inten;
    gl_FragColor = vec4(color,1);

}

Для трансформации камеры я использовал:

public static void applyTranslations() {
    glPushAttrib(GL_TRANSFORM_BIT);
    glMatrixMode(GL_MODELVIEW);
    glRotatef(pitch, 1, 0, 0);
    glRotatef(yaw, 0, 1, 0);
    glRotatef(roll, 0, 0, 1);
    glTranslatef(-x, -y, -z);
    glPopAttrib();
}

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

Vector3f scale, rot, trans;
Matrix3f modelMatrix = new Matrix3f();
modelMatrix.setIdentity();
scale = new Vector3f(1,1,1);
rot = new Vector3f(xRot,yRot,zRot);
trans = new Vector3f(x,y,z);

Matrix4f.scale(scale, modelMatrix, modelMatrix);
Matrix4f.translate(trans, modelMatrix, modelMatrix);
Matrix4f.rotate((float) Math.toRadians(rot.z), new Vector3f(0,0,1), modelMatrix, modelMatrix);
Matrix4f.rotate((float) Math.toRadians(rot.y), new Vector3f(0,1,0), modelMatrix, modelMatrix);
Matrix4f.rotate((float) Math.toRadians(rot.x), new Vector3f(1,0,0), modelMatrix, modelMatrix);

FloatBuffer modelBuff = BufferUtils.createFloatBuffer(9);
modelMatrix.store(modelBuff);

int loc = ARBShaderObjects.glGetUniformLocationARB(e.m.shader.programID, "modelMatrix");
ARBShaderObjects.glUniformMatrix4ARB(loc, false, modelBuff);

И затем я изменил свой вершинный шейдер на:

uniform vec3 lightDir;
uniform modelMatrix;
varying vec3 normal;

void main()
{       
    normal = modelMatrix*gl_Normal;
    gl_Position = ftransform();
}

Это то, что я должен делать для создания и передачи матриц преобразования? Также есть ли другой способ повернуть камеру без использования glRotatef()?


person itszn    schedule 28.06.2013    source источник


Ответы (1)


vec3 lightDir = vec3(1,1,0) остается постоянным, а normal изменяется каждый раз при смене камеры.

Чтобы этого не произошло, убедитесь, что lightDir и normal находятся в одном месте. Вычислить dot перед преобразованием normal или преобразовать lightDir в gl_NormalMatrix, а затем вычислить dot.

В дополнение к эффекту, которого вы хотите достичь, у вас есть проблема с фрагментным шейдером: normal не нормализован. Это связано с тем, что линейная интерполяция единичных векторов не всегда дает единичный вектор.

Что вы должны сделать, это что-то вроде:

color*dot(normalize(normal),  transform_to_same_space(lightDir))*inten;

Некоторые мелкие недочеты во второй части:

Вы объявляете modelMatrix без типа.

Вы не можете преобразовать vec3 с матрицей 4x4. Вы можете дополнить gl_Normal 0, так как это вектор, или уменьшить матрицу до float3x3.

Вы используете Matrix4f.scale с Vector3f(1,1,1), и перевод не повлияет на векторы, поэтому modelMatrix ортонормирован. Однако в общем случае вы должны преобразовать gl_Normal с транспонированной инверсией modelMatrix.

person a.lasram    schedule 29.06.2013