2015-02-15 2 views
3

Я попытался реализовать нормальное отображение в моем приложении opengl, но я не могу заставить его работать.Нормальное сопоставление было ужасно неправильным

This - это диффузная карта (в которую я добавляю коричневый цвет), а this - это нормальная карта. (? В других местах, называемая бинормаль)

Для того, чтобы получить касательную и бикасательную векторы, я запускаю эту функцию для каждого треугольника в моей сетке:

void getTangent(const glm::vec3 &v0, const glm::vec3 &v1, const glm::vec3 &v2, 
const glm::vec2 &uv0, const glm::vec2 &uv1, const glm::vec2 &uv2, 
std::vector<glm::vec3> &vTangents, std::vector<glm::vec3> &vBiangents) 
{ 
    // Edges of the triangle : postion delta 
    glm::vec3 deltaPos1 = v1-v0; 
    glm::vec3 deltaPos2 = v2-v0; 

    // UV delta 
    glm::vec2 deltaUV1 = uv1-uv0; 
    glm::vec2 deltaUV2 = uv2-uv0; 

    float r = 1.0f/(deltaUV1.x * deltaUV2.y - deltaUV1.y * deltaUV2.x); 
    glm::vec3 tangent = (deltaPos1 * deltaUV2.y - deltaPos2 * deltaUV1.y)*r; 
    glm::vec3 bitangent = (deltaPos2 * deltaUV1.x - deltaPos1 * deltaUV2.x)*r; 

    for(int i = 0; i < 3; i++) { 
     vTangents.push_back(tangent); 
     vBiangents.push_back(bitangent); 
    } 
} 

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

#version 430 

uniform mat4 ProjectionMatrix; 
uniform mat4 CameraMatrix; 
uniform mat4 ModelMatrix; 

in vec3 vertex; 
in vec3 normal; 
in vec2 uv; 
in vec3 tangent; 
in vec3 bitangent; 

out vec2 fsCoords; 
out vec3 fsVertex; 
out mat3 TBNMatrix; 

void main() 
{ 
    gl_Position = ProjectionMatrix * CameraMatrix * ModelMatrix * vec4(vertex, 1.0); 

    fsCoords = uv; 
    fsVertex = vertex; 

    TBNMatrix = mat3(tangent, bitangent, normal); 
} 

Фрагмент шейдеры:

#version 430 

uniform sampler2D diffuseMap; 
uniform sampler2D normalMap; 
uniform mat4 ModelMatrix; 
uniform vec3 CameraPosition; 

uniform struct Light { 
    float ambient; 
    vec3 position; 
} light; 
uniform float shininess; 

in vec2 fsCoords; 
in vec3 fsVertex; 
in mat3 TBNMatrix; 

out vec4 color; 

void main() 
{ 
    //base color 
    const vec3 brownColor = vec3(153.0/255.0, 102.0/255.0, 51.0/255.0); 
    color = vec4(brownColor * (texture(diffuseMap, fsCoords).rgb + 0.25), 1.0);//add a fixed base color (0.25), because its dark as hell 

    //general vars 
    vec3 normal = texture(normalMap, fsCoords).rgb * 2.0 - 1.0; 
    vec3 surfacePos = vec3(ModelMatrix * vec4(fsVertex, 1.0)); 
    vec3 surfaceToLight = normalize(TBNMatrix * (light.position - surfacePos)); //unit vector 
    vec3 eyePos = TBNMatrix * CameraPosition; 

    //diffuse 
    float diffuse = max(0.0, dot(normal, surfaceToLight)); 

    //specular 
    float specular; 
    vec3 incidentVector = -surfaceToLight; //unit 
    vec3 reflectionVector = reflect(incidentVector, normal); //unit vector 
    vec3 surfaceToCamera = normalize(eyePos - surfacePos); //unit vector 
    float cosAngle = max(0.0, dot(surfaceToCamera, reflectionVector)); 
    if(diffuse > 0.0) 
     specular = pow(cosAngle, shininess); 

    //add lighting to the fragment color (no attenuation for now) 
    color.rgb *= light.ambient; 
    color.rgb += diffuse + specular; 
} 

Изображение я совершенно неправильно. (свет, расположенный на камере) horrible results

Что я здесь делаю неправильно?

+0

Моя ставка на установке цвета/смешивания в пиксельный шейдер ... 1. Вы устанавливаете цвет вывода более чем один раз (если я правильно помню, на некоторых водителей GFX, что делать большие проблемы). 2. Вы добавляете «цвет» и «интенсивность» вместо «интенсивности цвета», но я мог упускать из виду. 3. Сначала попробуйте только обычное/ударное затенение (игнорируйте окружающее, отражайте, зеркально ...), а затем, если он работает, добавьте остальные по одному ...всегда проверяйте журналы компиляции шейдеров – Spektre

+0

Что касается 3, вы имеете в виду, что я должен использовать только диффузное освещение? Также как проверить журналы компиляции шейдеров? Мой компилятор не знаком с glsl, но только с C++. – Pilpel

+0

Да, вы должны установить переменную цвета только один раз и для начала с чем-то вроде этого: 'color.rgb = browncolor.rgb * fabs (dot (surface_normal, light_direction));' также добавил ответ с моими шейдерами, которые делают что-то похожее чего вы хотите достичь. Если вы не проверяете журналы, вы можете легко пропустить некоторые вещи, такие как оптимизированные переменные ввода/вывода, синтаксические ошибки и т. Д. – Spektre

ответ

7

Моя ставка на установке цвета/смешивания в пиксельный шейдер ...

  1. вы устанавливаете выходной цвет более раз

    Если я правильно помню, на некоторых водителей GFX, которые делают большие проблемы, например все после строки

    color = vec4(brownColor * (texture(diffuseMap, fsCoords).rgb + 0.25), 1.0);//add a fixed base color (0.25), because its dark as hell 
    

    может быть удален драйвер ...

  2. вы добавляете color и intensities вместо color*intensity

    , но я мог проглядеть коснуться.

  3. попробовать просто нормальным/врезаться затенением на первом

    Игнорирование эмбиента, отражает, зеркальный ... а затем, если он работает добавить остальное один за другим. Всегда проверяйте компиляции журналы шейдера

Лень для дальнейшего анализа кода, так вот как я это делаю:

bump mapping example

левый размер объекта космического корабля (по аналогии с ZXS Elite's Viper) с фиксированной функцией.Правая сторона того же (немного отличается вращение объекта) с GLSL шейдера на месте, и это нормально/врезаться карту

enter image description here

[Вершина]

//------------------------------------------------------------------ 
#version 420 core 
//------------------------------------------------------------------ 
// texture units: 
// 0 - texture0 map 2D rgba 
// 1 - texture1 map 2D rgba 
// 2 - normal map 2D xyz 
// 3 - specular map 2D i 
// 4 - light map 2D rgb rgb 
// 5 - enviroment/skybox cube map 3D rgb 

uniform mat4x4 tm_l2g; 
uniform mat4x4 tm_l2g_dir; 
uniform mat4x4 tm_g2s; 

uniform mat4x4 tm_l2s_per; 
uniform mat4x4 tm_per; 

layout(location=0) in vec3 pos; 
layout(location=1) in vec4 col; 
layout(location=2) in vec2 txr; 
layout(location=3) in vec3 tan; 
layout(location=4) in vec3 bin; 
layout(location=5) in vec3 nor; 

out smooth vec3 pixel_pos; 
out smooth vec4 pixel_col; 
out smooth vec2 pixel_txr; 
//out flat mat3 pixel_TBN; 
out smooth mat3 pixel_TBN; 
//------------------------------------------------------------------ 
void main(void) 
    { 
    vec4 p; 
    p.xyz=pos; 
    p.w=1.0; 
    p=tm_l2g*p; 
    pixel_pos=p.xyz; 
    p=tm_g2s*p; 
    gl_Position=p; 
    pixel_col=col; 
    pixel_txr=txr; 
    p.xyz=tan.xyz; p.w=1.0; pixel_TBN[0]=normalize((tm_l2g_dir*p).xyz); 
    p.xyz=bin.xyz; p.w=1.0; pixel_TBN[1]=normalize((tm_l2g_dir*p).xyz); 
    p.xyz=nor.xyz; p.w=1.0; pixel_TBN[2]=normalize((tm_l2g_dir*p).xyz); 
    } 
//------------------------------------------------------------------ 

[Фрагмент]

//------------------------------------------------------------------ 
#version 420 core 
//------------------------------------------------------------------ 
in smooth vec3 pixel_pos; 
in smooth vec4 pixel_col; 
in smooth vec2 pixel_txr; 
//in flat mat3 pixel_TBN; 
in smooth mat3 pixel_TBN; 

uniform sampler2D txr_texture0; 
uniform sampler2D txr_texture1; 
uniform sampler2D txr_normal; 
uniform sampler2D txr_specular; 
uniform sampler2D txr_light; 
uniform samplerCube txr_skybox; 

const int _lights=3; 
uniform vec3 light_col0=vec3(0.1,0.1,0.1); 
uniform vec3 light_dir[_lights]=   // direction to local star in ellipsoid space 
    { 
    vec3(0.0,0.0,+1.0), 
    vec3(0.0,0.0,+1.0), 
    vec3(0.0,0.0,+1.0), 
    }; 
uniform vec3 light_col[_lights]=   // local star color * visual intensity 
    { 
    vec3(1.0,0.0,0.0), 
    vec3(0.0,1.0,0.0), 
    vec3(0.0,0.0,1.0), 
    }; 

out layout(location=0) vec4 frag_col; 

const vec4 v05=vec4(0.5,0.5,0.5,0.5); 
const bool _blend=false; 
const bool _reflect=true; 
//------------------------------------------------------------------ 
void main(void) 
    { 
    float a=0.0,b,li; 
    vec4 col,blend0,blend1,specul,skybox; 
    vec3 normal; 
    col=(texture2D(txr_normal,pixel_txr.st)-v05)*2.0;  // normal/bump maping 
// normal=pixel_TBN*col.xyz; 
    normal=pixel_TBN[0]; 
    blend0=texture(txr_texture0,pixel_txr.st); 
    blend1=texture(txr_texture1,pixel_txr.st); 
    specul=texture(txr_specular,pixel_txr.st); 
    skybox=texture(txr_skybox,normal); 

    if (_blend) 
     { 
     a=blend1.a; 
     blend0*=1.0-a; 
     blend1*=a; 
     blend0+=blend1; 
     blend0.a=a; 
     } 

    col.xyz=light_col0; col.a=0.0; li=0.0;       // normal shading (aj s bump mapingom) 
    for (int i=0;i<_lights;i++) 
      { 
      b=dot(light_dir[i],normal.xyz); 
      if (b<0.0) b=0.0; 
//   b*=specul.r; 
      li+=b; 
      col.xyz+=light_col[i]*b; 
      } 
    col*=blend0; 
    if (li<=0.1) 
     { 
     blend0=texture2D(txr_light,pixel_txr.st); 
     blend0*=1.0-a; 
     blend0.a=a; 
     col+=blend0; 
     } 
    if (_reflect) col+=skybox*specul.r; 
     col*=pixel_col; 
    if (col.r<0.0) col.r=0.0; 
    if (col.g<0.0) col.g=0.0; 
    if (col.b<0.0) col.b=0.0; 
    a=0.0; 
    if (a<col.r) a=col.r; 
    if (a<col.g) a=col.g; 
    if (a<col.b) a=col.b; 
    if (a>1.0) 
     { 
     a=1.0/a; 
     col.r*=a; 
     col.g*=a; 
     col.b*=a; 
     } 
    frag_col=col; 
    } 
//------------------------------------------------------------------ 

Эти исходные коды немного устарели и смешиваются с разными вещами для конкретного применения.

Так что извлеките только то, что вам нужно от него. Если вы запутались с именами переменными, то комментарий меня ...

  • tm_ стендов для матрицы преобразования
  • l2g стендов для локальной системы координат глобальной системы координат преобразования
  • dir означает, что преобразование изменяет только направление (смещение 0,0,0)
  • g2s стенды для глобального экранировать ...
  • per это перспективное преобразование ...

GLSL сборник журнал

Вы должны получить его содержание programaticaly после компиляции вашего шейдера (не приложения !!!). Я делаю это с вызовом функции glGetShaderInfoLog для каждого шейдера программы я использую ...

[Примечания]

Некоторых водителей оптимизировать «неиспользуемые» переменный. Как вы можете видеть на картинке txr_texture1 не найден, даже если шейдер фрагмента имеет его в коде, но смешение не используется в этом приложении, поэтому драйвер удалил его самостоятельно ...

Шейдерные журналы могут показать вам много (синтаксические ошибки, предупреждения ...)

Есть несколько GLSL IDE для создания шейдера, но я предпочитаю его, потому что я могу использовать в нем целевой код приложения напрямую. Шахта выглядит следующим образом:

GLSL IDE

каждое окно TXT является источником шейдера (вершина, фрагмент, ...) правый низ буфер, левая вершина журнал шейдера после последней компиляции и слева внизу является просмотр , Мне удалось прописать его как IDE в Borland (с ключевыми клавишами и подсветкой синтаксиса), другие IDE, которые я видел, выглядят одинаково (разные цвета грубо :)) в любом случае, если вы хотите играть с загрузкой шейдера таким приложением или делать это самостоятельно поможет много ...

Там может быть также проблемы с созданием ТБН

Вы должны визуально проверить, если TBN векторы (тангенс, бинормальная, нормальная) соответствуют объекту поверхности путем рисования цветные линии на каждой позиции вершины. Просто чтобы быть уверенным ... что-то вроде этого:

normals

+0

@Pilpel мелко закончить редактирование проверить ответ и прокомментировать меня, если вам нужна дополнительная помощь ... – Spektre

+0

Спасибо за ваш ответ, у вас не было много времени, чтобы проанализировать ваш код (он тоже не очень читается), но я буду, как только смогу. Просто что бы ты знал.. – Pilpel

0

Я постараюсь, чтобы сделать ваш код работать. Вы пробовали его с движущейся камерой?

Я не вижу нигде, что вы преобразовали TBNMatrix с матрицами преобразования, представления и модели. Вы попробовали исходные нормали vec3 normal = TBNMatrix[2];? (Фрагментный шейдер)

Возможно, это поможет. В затенении Vertex у вас есть:

uniform mat4 ProjectionMatrix; 
uniform mat4 CameraMatrix; 
uniform mat4 ModelMatrix; 

Однако здесь следует использовать только эти 3 матрицы:

uniform mat4 PCM; 
uniform mat4 MIT;   //could be mat3 
uniform mat4 ModelMatrix; //could be mat3 

Это более эффективно вычислить произведение этих матриц на CPU (и дает тот же потому что матричное умножение ассоциативно). Затем этот продукт, РСМ может быть использован как для расчета новой позиции с одним умножением на вершину:

gl_Position = PCM * vec4(vertex, 1.0); 

MIT обратная транспонированная ModelMatrix, вы должны вычислить его на CPU. Это может быть использовано преобразование нормалей:

vec4 tang = ModelMatrix*vec4(tangent,0); 
vec4 bita= ModelMatrix*vec4(bitangent,0); 
vec4 norm= PCMIT*vec4(tangent,0); 
TBNMatrix = mat3(normalize(tang.xyz), normalize(bita.xyz), normalize(normal.xyz)); 

Я не уверен, что происходит с касательной и бикасательная, но этот путь нормальный будет оставаться перпендикулярно к ним. Легко доказать. Здесь я использую a ° b как скалярное произведение векторов a и b. Итак, пусть n - некоторая нормаль, a - некоторый вектор на поверхности (например, {bi} касательная, край треугольника), и пусть A - любое преобразование. Тогда:

0 = а = А^(- 1) а ° п = Аа ° А^(- Т) п = 0

Где используется равенство А х ° у = х ° А^T y. Поэтому, если а перпендикулярно п, то А а перпендикулярно А^(- Т) п, поэтому мы должны преобразовать его с помощью обратного транспонирования матрицы. Однако норма должна иметь длину 1, поэтому после преобразований она должна быть нормализована.

Вы можете получить также получить перпендикулярную нормально, делая это:

vec3 normal = normalize(cross(tangent, bitangent)); 

Где крест (а, Ь) функция, которая вычисляет декартово произведение а и Ь, ведьма всегда перпендикулярна как а и Ь ,

Извините за мой английский :)