Нечетный эффект с нормалью GLSL
В некоторой степени похожая на проблему, с которой я сталкивался раньше и опубликовал ранее, я пытаюсь заставить нормально отображаться нормали в моем приложении GLSL. В целях моего объяснения я использую модель ninjaHead.obj, поставляемую с RenderMonkey, для тестирования ( вы можете получить ее здесь). Теперь в окне предварительного просмотра в RenderMonkey все выглядит отлично:и код вершины и фрагмента, сгенерированный соответственно:
Vertex:
uniform vec4 view_position;
varying vec3 vNormal;
varying vec3 vViewVec;
void main(void)
{
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
// World-space lighting
vNormal = gl_Normal;
vViewVec = view_position.xyz - gl_Vertex.xyz;
}
Фрагмент:
uniform vec4 color;
varying vec3 vNormal;
varying vec3 vViewVec;
void main(void)
{
float v = 0.5 * (1.0 + dot(normalize(vViewVec), vNormal));
gl_FragColor = v* color;
}
Я основал свой код GLSL на этом, но я не совсем получаю ожидаемые результаты...
Код моего вершинного шейдера:
uniform mat4 P;
uniform mat4 modelRotationMatrix;
uniform mat4 modelScaleMatrix;
uniform mat4 modelTranslationMatrix;
uniform vec3 cameraPosition;
varying vec4 vNormal;
varying vec4 vViewVec;
void main()
{
vec4 pos = gl_ProjectionMatrix * P * modelTranslationMatrix * modelRotationMatrix * modelScaleMatrix * gl_Vertex;
gl_Position = pos;
gl_TexCoord[0] = gl_MultiTexCoord0;
gl_FrontColor = gl_Color;
vec4 normal4 = vec4(gl_Normal.x,gl_Normal.y,gl_Normal.z,0);
// World-space lighting
vNormal = normal4*modelRotationMatrix;
vec4 tempCameraPos = vec4(cameraPosition.x,cameraPosition.y,cameraPosition.z,0);
//vViewVec = cameraPosition.xyz - pos.xyz;
vViewVec = tempCameraPos - pos;
}
Мой фрагмент кода шейдера:
varying vec4 vNormal;
varying vec4 vViewVec;
void main()
{
//gl_FragColor = gl_Color;
float v = 0.5 * (1.0 + dot(normalize(vViewVec), vNormal));
gl_FragColor = v * gl_Color;
}
Однако мой рендер производит это...
Кто-нибудь знает, что может быть причиной этого и / или как заставить это работать?
РЕДАКТИРОВАТЬ В ответ на комментарии kvark, вот модель, представленная без каких-либо нормальных / световых расчетов, чтобы показать все визуализируемые треугольники.
А вот модель затенения с нормалями, используемыми для цветов. Я считаю, что проблема была найдена! Теперь причина в том, почему это делается так и как это решить? Предложения приветствуются!
РЕШЕНИЕ Ну, все проблемы были решены! Спасибо kvark за всю его полезную информацию, которая определенно помогла моей практике программирования, но я боюсь, что ответ исходит от меня, как МАССОВОЙ синицы... У меня произошла ошибка в функции display() моего кода, которая установила смещение glNormalPointer к случайному значению. Раньше было так:
gl.glEnableClientState(GL.GL_NORMAL_ARRAY);
gl.glBindBuffer(GL.GL_ARRAY_BUFFER, getNormalsBufferObject());
gl.glNormalPointer(GL.GL_FLOAT, 0, getNormalsBufferObject());
Но должно было быть так:
gl.glEnableClientState(GL.GL_NORMAL_ARRAY);
gl.glBindBuffer(GL.GL_ARRAY_BUFFER, getNormalsBufferObject());
gl.glNormalPointer(GL.GL_FLOAT, 0, 0);
Так что, думаю, это урок. НИКОГДА бездумно не нажимайте Ctrl+C и Ctrl+V, чтобы сэкономить время в пятницу днем И... Когда вы уверены, что часть кода, на которую вы обращаетесь, верна, проблема, вероятно, где-то еще!
2 ответа
Какой твой
P
матрица? (Полагаю, это трансформация вида мир-> камера).vNormal = normal4*modelRotationMatrix;
Почему вы изменили порядок аргументов? Делая это, вы умножаете нормальное на обратное вращение, что вы на самом деле не хотите. Вместо этого используйте стандартный порядок (modelRotationMatrix * normal4)vViewVec = tempCameraPos - pos
, Это совершенно неверно.pos
ваша вершина в однородном пространстве клипа, в то время какtempCameraPos
находится в мировом пространстве (я полагаю). Вы должны иметь результат в том же пространстве, что и ваша нормаль (мировое пространство), поэтому используйте положение вершины мирового пространства (modelTranslationMatrix * modelRotationMatrix * modelScaleMatrix * gl_Vertex
) для этого уравнения.
Вы, кажется, немного смешиваете версии GL? Вы передаете матрицы вручную через униформу, но используете фиксированную функцию для передачи атрибутов вершин. Гектометр Тем не мение...
Мне искренне не нравится, что ты делаешь со своими нормальными. Посмотри:
vec4 normal4 = vec4(gl_Normal.x,gl_Normal.y,gl_Normal.z,0);
vNormal = normal4*modelRotationMatrix;
Нормальный хранит только направленные данные, зачем использовать vec4
для этого? Я считаю, что более элегантно просто использовать vec3
, Кроме того, посмотрите, что происходит дальше - вы умножаете нормаль на матрицу вращения модели 4x4... И, кроме того, четвертый кординат вашего нормаля равен 0, так что это неправильный вектор в однородных координатах. Я не уверен, что это главная проблема здесь, но я не удивлюсь, если это умножение даст вам мусор.
Стандартный способ преобразования нормалей состоит в умножении vec3
подматрицей 3x3 матрицы вида модели (поскольку вас интересует только ориентация, а не перевод). Точно, подход "correctest" заключается в использовании обратной транспонирования этой подматрицы 3x3 (это важно при масштабировании). В старых версиях OpenGL он был предварительно рассчитан как gl_NormalMatrix
,
Таким образом, вместо вышеупомянутого, вы должны использовать что-то вроде
// (...)
varying vec3 vNormal;
// (...)
mat3 normalMatrix = transpose(inverse(mat3(modelRotationMatrix)));
// or if you don't need scaling, this one should work too-
mat3 normalMatrix = mat3(modelRotationMatrix);
vNormal = gl_Normal*normalMatrix;
Это, безусловно, одна вещь, которую нужно исправить в вашем коде - надеюсь, это решит вашу проблему.