简体   繁体   English

glsl片段着色器如何从每个顶点获取非插值数据

[英]glsl fragment shader how to get non-interpolated data from each vertex

tl;dr: What is the best method for accessing data from each individual vertex whilst in the fragment shader? tl; dr:片段着色器中从每个顶点访问数据的最佳方法是什么?

eg The triangle in this fragment is made up from vertices v0,v1 and v2 and I want to give each vertex a specific integer which I can use to pick a texture and then fade between the 3 in the fragment shader; 例如 ,这个片段中的三角形是由顶点v0,v1和v2组成的,我想给每个顶点一个特定的整数,我可以用它来挑选一个纹理,然后在片段着色器中的3之间淡出; I don't want these ids to be interpolated and it is important that I can access each vertex's id. 我不希望插入这些id,重要的是我可以访问每个顶点的id。

Current Situation: I am currently writing a shader for rendering terrain; 现状:我目前正在为渲染地形编写一个着色器; I have a function in my fragment shader which will return the appropriate texture colour from uvs for a given ID (By means of a texture atlas). 我的片段着色器中有一个函数,它将从给定ID的uvs返回适当的纹理颜色(通过纹理图集)。 I can then fade between the 3 textures to give the give smoothly textured terrain 然后我可以在3个纹理之间淡入淡出,给出平滑的纹理地形

Current Code 现行守则

Vertex Shader: 顶点着色器:

#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();
}

Fragment Shader: 片段着色器:

#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();
}

By default the output variables from the vertex shader to the fragment shader use perspective-correct interpolation. 默认情况下,从顶点着色器到片段着色器的输出变量使用透视校正插值。 If you want no interpolation done then qualify your variables with flat : 如果您不想进行插值,那么使用flat来限定变量:

flat out vec3 pass_id0;

For more info see GLSL Type Qualifiers . 有关更多信息,请参阅GLSL类型限定符 Also see this question “flat” qualifier in glsl? 还可以在glsl中看到这个问题“flat”限定符吗?

As recommended by @aslg and @AndonM.Coleman, geometry is a good solution to this issue. 根据@aslg和@AndonM.Coleman的建议,几何是这个问题的一个很好的解决方案。 A flat vec3 is passed out of the geometry stage, which stores the id of each vertex which is then accessible in the fragment shader. 从几何阶段传出一个平面vec3,它存储每个顶点的id,然后可以在片段着色器中访问它。

The key lines are in the geometry shader; 关键线在几何着色器中; one part of the output is 输出的一部分是

flat vec3 texture_ids;

Which is then set as such: 然后将其设置为:

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;

Full Shader Sources: 完整着色器来源:

Vertex 顶点

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

Geometry 几何

#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();
}

Fragment 分段

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM