Нечетный эффект с нормалью GLSL - PullRequest
4 голосов
/ 20 апреля 2011

В некоторой степени похоже на проблему, с которой я сталкивался ранее и публиковал ранее, я пытаюсь настроить нормальное отображение в моем приложении GLSL.В целях моего объяснения я использую модель ninjaHead.obj, поставляемую с RenderMonkey, для целей тестирования ( вы можете получить ее здесь ).Теперь в окне предварительного просмотра в RenderMonkey все выглядит великолепно: RenderMonkey и генерируемый код вершины и фрагмента соответственно:

Вершина:

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;
}

Однако мой рендер производит это ... openGL render

Кто-нибудь знает, что может быть причиной и / или как заставить это работать?

РЕДАКТИРОВАТЬ В ответ на комментарии kvark, вот модель, представленная без каких-либо нормальных / осветительных расчетов, чтобы показать все визуализируемые треугольники.Render flat shading

А вот модель затенения с нормалями, используемыми для цветов.Я считаю, что проблема была найдена!Теперь причина в том, почему это делается так и как это решить?Предложения приветствуются!Normal shading

РЕШЕНИЕ Ну, всем проблема решена!Спасибо 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 ]

1 голос
/ 20 апреля 2011
  1. Какая у вас P матрица? (Полагаю, это трансформация вида "мир-> камера").

  2. vNormal = normal4*modelRotationMatrix; Почему вы изменили порядок аргументов? Делая это, вы умножаете нормальное на обратное вращение, чего вы на самом деле не хотите. Вместо этого используйте стандартный порядок (modelRotationMatrix * normal4)

  3. vViewVec = tempCameraPos - pos. Это совершенно неверно. pos - ваша вершина в однородном пространстве клипов, тогда как tempCameraPos - в мировом пространстве (я полагаю). Вам нужно, чтобы результат находился в том же пространстве, что и ваша нормаль (мировое пространство), поэтому используйте для этого уравнения положение вершины мирового пространства (modelTranslationMatrix * modelRotationMatrix * modelScaleMatrix * gl_Vertex).

0 голосов
/ 23 апреля 2011

Кажется, вы немного смешиваете версии 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;

Это, безусловно, одна вещь, которую нужно исправить в вашем коде - янадеюсь, что это решит вашу проблему.

...