Подвернулся мне как то под руку простенький шейдер бампа.
но после его прикручивания с источником света начала происходит какая то фигня, его позиция зависила от матрицы поворота камеры....
начал разбираться с языком, да и с бампом и понял что вершинный шейдер косячный и переделал его по своему.
вершинный шейдер
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, хотя позицию я кручу..
я в шейдерах не давно, подсмотрите профессиональным взглядом скажите что ни так.
У 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 соответственно (хотя кого-то из них можно и не считать
SashkaStudent
поставь себе RenderMonkey - там куча примеров
crsib
Ну вообщем не работает... :(
innuendo
Посмотрю что за весчица
SashkaStudent
> Ну вообщем не работает... :(
Что конкретно не работает? Учитывая что шейдер взят из работающего приложения, то проблема скорее всего в том, как устанавливаются матрицы
crsib
фрагментный шейдер надо править.... потому что артефакты начинаются на экране, а и сточник света так то косячно передвигается... кароче буду детально разбираться.
crsib
Можешь показать фрагментный шейдер, хотя бы в упрощенном варианте.
а tangent и binormal передается в шейдер?
>а 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.
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 );
}Тема в архиве.