2013-06-28 3 views
1

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

Вот мой оригинальный Vertex Shader:

uniform vec3 lightDir; 
varying vec3 normal; 

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

My Fragment Shader:

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()?

ответ

0

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.