2016-04-09 94 views
1

tl; dr: 在片段着色器中訪問各個頂點數據的最佳方法是什麼?glsl片段着色器如何從每個頂點獲取非插值數據

例如 在該片段的三角形頂點從V0,V1和V2由與我想給每個頂點,我可以使用選擇一個紋理的特定整數,然後在片段着色器3之間褪色;我不希望這些id被內插,重要的是我可以訪問每個頂點的id。

當前情況: 我目前正在編寫渲染地形的着色器;我在我的片段着色器中有一個函數,它將從uvs返回給定ID的合適紋理顏色(通過紋理圖集)。然後我可以在3個紋理之間褪色給予給順利紋理地形

目前代碼

頂點着色器:

#version 330 core 

layout(location = 0) in vec3 in_position; 
layout(location = 1) in vec2 in_uv_coords; 
layout(location = 2) in vec3 in_normal; 
layout(location = 3) in float in_texture_id; 

uniform mat4 view_matrix; 
uniform mat4 projection_matrix; 

out vec2 pass_uv_coords; 
out vec3 pass_normal; 

out vec3 texture_ratio; 
out float pass_fake_brightness; 

out float pass_id0; 
out float pass_id1; 
out float pass_id2; 


void CalculateFakeLighting() 
{ 
    const vec3 light_direction = normalize(vec3(1,-1,1)); 
    vec3 unit_normal = normalize(in_normal); 

    float normal_dot_light = dot(unit_normal, -light_direction); 
    pass_fake_brightness = max(0.2, normal_dot_light); 
} 


void main() 
{ 
    pass_uv_coords = in_uv_coords; 
    pass_normal = in_normal; 

    gl_Position = projection_matrix * view_matrix * vec4(in_position, 1.0); 

    int tile_track = int(mod(gl_VertexID, 3)); 

    switch(tile_track) 
    { 
     case 0: 
      texture_ratio = vec3(1,0,0); 
      pass_id0 = in_texture_id; 
      break; 
     case 1: 
      texture_ratio = vec3(0,1,0); 
      pass_id1 = in_texture_id; 
      break; 
     case 2: 
      texture_ratio = vec3(0,0,1); 
      pass_id0 = in_texture_id; 
      break; 
    }; 

    CalculateFakeLighting(); 
} 

片段着色器:

#version 330 core 

in vec2 pass_uv_coords; 
in vec3 pass_normal; 

in vec3 texture_ratio; 
in float pass_fake_brightness; 

in float pass_id0; 
in float pass_id1; 
in float pass_id2; 

const int HORIZONTAL_IDS = 8; 
const int VERTICAL_IDS = 8; 

uniform sampler2D texture0_sampler; 

out vec4 colour; 


void UseFakeLighting() 
{ 
    colour *= pass_fake_brightness; 
} 

vec2 CorrectUVs(vec2 uvs) 
{ 
    vec2 corrected_uvs = uvs; 
    const float cushion = 0.001; 

    //Correct UV scale 
    while(corrected_uvs.x >= 1) 
     corrected_uvs.x--; 
    while(corrected_uvs.y >= 1) 
     corrected_uvs.y--; 

    if(corrected_uvs.x < cushion) 
     corrected_uvs.x = cushion; 
    if(corrected_uvs.x > 1 - cushion) 
     corrected_uvs.x = 1 - cushion; 

    if(corrected_uvs.y < cushion) 
     corrected_uvs.y = cushion; 
    if(corrected_uvs.y > 1 - cushion) 
     corrected_uvs.y = 1 - cushion; 

    return corrected_uvs; 
} 


vec4 GetTexture(float id, vec2 uv_coords) 
{ 
    vec2 step = vec2(
     1.0/HORIZONTAL_IDS, 
     1.0/VERTICAL_IDS 
    ); 


    uv_coords.x/=HORIZONTAL_IDS; 
    uv_coords.y/=VERTICAL_IDS; 

    uv_coords.x += step.x * mod(id, HORIZONTAL_IDS); 
    uv_coords.y += step.y * floor(id/VERTICAL_IDS); 
    //Texture is upsidedown 
    uv_coords.y = 1.0 - uv_coords.y; 

    return texture(texture0_sampler, uv_coords); 
} 


void main() 
{ 
    vec2 corrected_uvs = CorrectUVs(pass_uv_coords); 
    vec3 correct_ratio = normalize(texture_ratio); 

    colour = GetTexture(pass_id0, corrected_uvs) * correct_ratio.x + 
    GetTexture(pass_id1, corrected_uvs) * correct_ratio.y + 
    GetTexture(pass_id2, corrected_uvs) * correct_ratio.z; 

    if(colour.a == 0) 
     discard; 

    UseFakeLighting(); 
} 

回答

1

所推薦的@aslg和@ AndonM.Coleman,幾何是一個很好的解決這個問題。平面vec3從幾何階段傳出,存儲每個頂點的ID,然後在片段着色器中訪問該頂點。

關鍵線位於幾何着色器中;輸出的一個部分是

flat vec3 texture_ids; 

,然後將其設置爲這樣:

vertex_out.texture_ids.x = vertex_in[0].texture_id; 
vertex_out.texture_ids.y = vertex_in[1].texture_id; 
vertex_out.texture_ids.z = vertex_in[2].texture_id; 

全部着色來源:

頂點

#version 330 core 

layout(location = 0) in vec3 in_position; 
layout(location = 1) in vec2 in_uv_coords; 
layout(location = 2) in vec3 in_normal; 
layout(location = 3) in float in_texture_id; 

out VertexData 
{ 
    vec2 uv_coord; 
    vec3 normal; 
    uint texture_id; 
} vertex_out; 


void main() 
{ 
    vertex_out.uv_coord = in_uv_coords; 
    vertex_out.normal = in_normal; 
    vertex_out.texture_id = uint(round(in_texture_id)); 
    gl_Position = vec4(in_position, 1.0); 
} 

幾何

#version 330 core 

layout (triangles) in; 
layout (triangle_strip, max_vertices = 3) out; 

uniform mat4 view_matrix; 
uniform mat4 projection_matrix; 
mat4 vp_matrix = projection_matrix * view_matrix; 

in VertexData 
{ 
    vec2 uv_coord; 
    vec3 normal; 
    uint texture_id; 
} vertex_in[]; 

out VertexDataPass 
{ 
    vec2 uv_coord; 
    vec3 normal; 
    vec3 texture_ratio; 
    float brightness; 
    flat vec3 texture_ids; 
} vertex_out; 


void CalculateFakeBrightness(int index) 
{ 
    const vec3 light_direction = normalize(vec3(1,-1,1)); 
    vec3 unit_normal = normalize(vertex_in[index].normal); 

    float normal_dot_light = dot(unit_normal, -light_direction); 
    vertex_out.brightness = max(0.2, normal_dot_light); 
} 


void main() 
{ 
    for(int i = 0; i < gl_in.length(); i++) 
    { 
     gl_Position = vp_matrix * gl_in[i].gl_Position; 
     vertex_out.uv_coord = vertex_in[i].uv_coord; 
     vertex_out.normal = vertex_in[i].normal; 

     vertex_out.texture_ids.x = vertex_in[0].texture_id; 
     vertex_out.texture_ids.y = vertex_in[1].texture_id; 
     vertex_out.texture_ids.z = vertex_in[2].texture_id; 
     CalculateFakeBrightness(i); 

     switch(int(mod(i,3))) 
     { 
      case 0: 
       vertex_out.texture_ratio = vec3(1,0,0); 
       break; 
      case 1: 
       vertex_out.texture_ratio = vec3(0,1,0); 
       break; 
      case 2: 
       vertex_out.texture_ratio = vec3(0,0,1); 
       break; 
     }; 

     EmitVertex(); 
    } 
    EndPrimitive(); 
} 

片段

#version 330 core 

in VertexDataPass 
{ 
    vec2 uv_coord; 
    vec3 normal; 
    vec3 texture_ratio; 
    float brightness; 
    flat vec3 texture_ids; 
} vertex_data; 

const int HORIZONTAL_IDS = 8; 
const int VERTICAL_IDS = 8; 
uniform sampler2D texture0_sampler; 

out vec4 colour; 


vec2 CorrectUVs(vec2 uvs) 
{ 
    vec2 corrected_uvs = uvs; 
    const float cushion = 0.001; 

    //Correct UV scale 
    while(corrected_uvs.x >= 1) 
     corrected_uvs.x--; 
    while(corrected_uvs.y >= 1) 
     corrected_uvs.y--; 

    if(corrected_uvs.x < cushion) 
     corrected_uvs.x = cushion; 
    if(corrected_uvs.x > 1 - cushion) 
     corrected_uvs.x = 1 - cushion; 

    if(corrected_uvs.y < cushion) 
     corrected_uvs.y = cushion; 
    if(corrected_uvs.y > 1 - cushion) 
     corrected_uvs.y = 1 - cushion; 

    return corrected_uvs; 
} 


vec4 GetTexture(uint id, vec2 uv_coords) 
{ 
    vec2 step = vec2(
     1.0/HORIZONTAL_IDS, 
     1.0/VERTICAL_IDS 
    ); 


    uv_coords.x/=HORIZONTAL_IDS; 
    uv_coords.y/=VERTICAL_IDS; 

    uv_coords.x += step.x * mod(id, HORIZONTAL_IDS); 
    uv_coords.y += step.y * floor(float(id)/VERTICAL_IDS); 
    //Texture is upsidedown 
    uv_coords.y = 1.0 - uv_coords.y; 

    return texture(texture0_sampler, uv_coords); 
} 


void main() 
{ 
    vec2 uvs = CorrectUVs(vertex_data.uv_coord); 

    colour = 
     GetTexture(uint(vertex_data.texture_ids.x), uvs) * vertex_data.texture_ratio.x + 
     GetTexture(uint(vertex_data.texture_ids.y), uvs) * vertex_data.texture_ratio.y + 
     GetTexture(uint(vertex_data.texture_ids.z), uvs) * vertex_data.texture_ratio.z; 

    if(colour.a == 0) 
     discard; 

    colour.xyz *= vertex_data.brightness; 
} 
2

默認情況下,從頂點着色器到片段着色器的輸出變量使用透視正確插值。如果你不想要做插值然後用flat資格的變量:

flat out vec3 pass_id0; 

欲瞭解更多信息請參閱GLSL Type Qualifiers。也看到這個問題「flat」 qualifier in glsl?

+0

我知道,但它只會通過值pass_id0爲三角形的最後一個頂點,我需要從所有頂點 –

+0

的價值,你在哪裏看的?挑動頂點完全由用戶定義。你是正確的,激發頂點默認是最後一個,但描述你所做的是正確的方式是指「激發頂點」;)然而,如果你正在做一些需要來自多個頂點的值,它確實聽起來像像你想在早期階段(幾何着色器,也許?)做這個計算 –

+0

@ AndonM.Coleman我還沒有觸及幾何着色器,所以我會讀它。我可以輸出類似於vec3的東西,它從幾何着色器的每個頂點存儲特定值到片段着色器? –

相關問題