ПрограммированиеФорумГрафика

GLSL и источник света... Как его повернуть?=)))

#0
12:15, 16 окт 2009

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

вершинный шейдер

uniform vec3 light_position;
attribute vec3 tangent; 
varying vec3 light_direction; 
varying vec3 eye_direction;
varying vec2 texCoord;

void main()
{
   gl_Position = ftransform();

   texCoord = gl_MultiTexCoord0.xy;

    vec3 n = normalize(gl_NormalMatrix * gl_Normal);
    vec3 t = normalize(gl_NormalMatrix * tangent);
    vec3 b = cross(n, t);

   vec3 vVertex =gl_NormalMatrix * (gl_ModelViewMatrixInverse[3].xyz - gl_Vertex.xyz);
   vec3 tmp = (light_position - gl_Vertex.xyz);

light_direction=(tmp); \\направление источника света 

//если его умножать на TBN то получаецо что источние света зависит от позиции камеры, поэтому я это зачеркнул
//  light_direction.x = dot(tmp, t);
//  light_direction.y = dot(tmp, b);
//  light_direction.z = dot(tmp, n);

   tmp = vVertex;               
   eye_direction.x = dot(tmp, t);
   eye_direction.y = dot(tmp, b);
   eye_direction.z = dot(tmp, n);
}

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

varying vec3 light_direction; 
varying vec3 eye_direction;
varying vec2 texCoord;

uniform vec3 light; // Light Colour;
uniform vec3 ambient;
uniform vec3 specular;
uniform float exponent;

uniform sampler2D normal_map;
uniform sampler2D colour_map;

void main()
{
   float inverse_radius = 0.00125;

   float distance_sqr = dot(light_direction, light_direction);
   float att = clamp(1.0 - inverse_radius * sqrt(distance_sqr), 0.0, 1.0);
 
   vec3 l = light_direction * inversesqrt(distance_sqr);
   vec3 v = normalize(eye_direction);

     vec3 base = texture2D(colour_map, texCoord).xyz;
   vec3 bump =normalize( texture2D(normal_map, texCoord).xyz * 2.0 - 1.0);

   float d = dot(l, bump);
   float r = dot(reflect(-l, bump), v);

   vec3 color =  base * (ambient + light * max(0.0, d)) /* Ambient lighting. */;
        color += light * specular * pow(clamp(r, 0.0, 1.0), exponent); /* Phong exponent. */

   gl_FragColor = vec4(color, 0.0) * att;
}

После моих переделок можно задавать позицию источнику света, но повернуть его не получаецо, он светит всегда паралельно оси X, хотя позицию я кручу..

Изображение удалено

я в шейдерах не давно, подсмотрите профессиональным взглядом скажите что ни так.

#1
12:37, 16 окт 2009

У OpenGL есть такая забавная особенность - у него только две "стандартные" матрицы преобразования. Что бы была возможность передавать позицию и ориентацию источника света в world space (всмысле до примения преобразования камеры к вершинам) эту самую матрицу камеры лучше умножать на projection матрицу. Тогда вершинный шейдер упростится до безобразия:

varying  vec3 lt;
varying  vec3 ht;

uniform  vec3  lightPos;
uniform vec3  eyePos;

void main(void)
{
  vec3  p = vec3      ( gl_ModelViewMatrix * gl_Vertex );    // transformed point to world space
  vec3  l = normalize ( lightPos  - p );          // vector to light source
  vec3  v = normalize ( eyePos - p );          // vector to the eye
  vec3  h = normalize ( l + v );

  vec3  n = gl_NormalMatrix * gl_Normal;        // transformed n

  vec3 t = gl_NormalMatrix * gl_MultiTexCoord1.xyz;          // transformed t
  vec3 b = gl_NormalMatrix * gl_MultiTexCoord2.xyz;    // transformed b
  // now remap l, and h into tangent space
  lt = vec3 ( dot ( l, t ), dot ( l, b ), dot ( l, n ) );
  ht = vec3 ( dot ( h, t ), dot ( h, b ), dot ( h, n ) );

  gl_Position     = gl_ModelViewProjectionMatrix * gl_Vertex;
  gl_TexCoord [0] = gl_MultiTexCoord0;
}

в данном случае lt = light_direction; ht ~ eye_direction;
касательное направление и бинормаль передаются через TEX_COORD1 и TEX_COORD2 соответственно (хотя кого-то из них можно и не считать

#2
16:50, 16 окт 2009

SashkaStudent

поставь себе RenderMonkey - там куча примеров

#3
17:52, 16 окт 2009

crsib
Ну вообщем не работает... :(

innuendo
Посмотрю что за весчица

#4
18:00, 16 окт 2009

SashkaStudent
> Ну вообщем не работает... :(
Что конкретно не работает? Учитывая что шейдер взят из работающего приложения, то проблема скорее всего в том, как устанавливаются матрицы

#5
13:02, 17 окт 2009

crsib
фрагментный шейдер надо править.... потому что артефакты начинаются на экране, а и сточник света так то косячно передвигается... кароче буду детально разбираться.

#6
14:30, 17 окт 2009

crsib
Можешь показать фрагментный шейдер, хотя бы в упрощенном варианте.

#7
21:37, 17 окт 2009

а tangent и binormal передается в шейдер?

#8
22:29, 17 окт 2009

>а tangent и binormal передается в шейдер?
да
в вершинном шейдере:
tmp= (light_position - gl_Vertex.xyz); направление источника света
light_direction=tmp;
//если light_direction умножать на TBN то получаецо что источние света зависит от ориентации камеры, поэтому я это зачеркнул, хотя в примере (ссылка на который в первом посте), они умножают.... может они как то по другому задают позицию, но у меня большие косяки тогда возникают.
Я честно говоря сам не понимаю зачем надо умножать луч света на TBN.
//  light_direction.x = dot(tmp, t);
//  light_direction.y = dot(tmp, b);
//  light_direction.z = dot(tmp, n);

в eye_direction передаётся:
  tmp = gl_NormalMatrix * (gl_ModelViewMatrixInverse[3].xyz - gl_Vertex.xyz);
//умножаем на TBN
  eye_direction.x = dot(tmp, t);
  eye_direction.y = dot(tmp, b);
  eye_direction.z = dot(tmp, n);


во фрагментном шейдере работа уже идёт eye_direction и light_direction.

#9
19:46, 18 окт 2009

SashkaStudent
> Можешь показать фрагментный шейдер, хотя бы в упрощенном варианте.
Сорри за задержку, был далеко от ноута и рядом с виски.
Если еще актуально - то вот он:

varying  vec3 lt;
varying  vec3 ht;

uniform sampler2D bump;      // Bump map
uniform sampler2D diffuse;    // Diffuse map
uniform sampler2D specular;  //Specular map


void main (void)
{
  vec3  n    = texture2D ( bump, gl_TexCoord [0].xy ).rgb;    // get normal perturbation
  vec3  nt   = normalize ( 2.0*n - 1.0 ); //[0,1]->[-1,1]
  vec3  l2   = normalize ( lt );
  vec3  h2   = normalize ( ht );
  float  diff = max ( dot ( nt, l2 ), 0.0 );
  float  spec = pow ( max ( dot ( nt, h2 ), 0.0 ), 30.0 );

  gl_FragColor = diff * texture2D ( diffuse, gl_TexCoord [0].xy ) + spec * texture2D ( specular, gl_TexCoord [0].xy );
}
ПрограммированиеФорумГрафика

Тема в архиве.